bzoj 1894 游戏

题目大意:

$n$个装备,每个装备有两个值,可以攻击该值对应的怪兽。每个装备最多用一次

每个怪兽被打一次之后就会死,每个怪兽可以被打当且仅当前面的都死了,求最多打多少个

思路:

很明显的二分图匹配,如果用$Dinic$的时候一条一条加入连向终点的边即可

但是为什么这道题我$TLE$了啊 垃圾Dinic要你有何用,我也不(wang)会(le)匈牙利啊

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<cmath>
 6 #include<algorithm>
 7 #include<queue>
 8 #include<vector>
 9 #include<map>
10 #include<set>
11 #define ll long long
12 #define db double
13 #define inf 2139062143
14 #define MAXN 4010
15 #define MOD 1000000007
16 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i)
17 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i)
18 #define ren for(register int i=fst[x];i;i=nxt[i])
19 #define pb(i,x) vec[i].push_back(x)
20 #define pls(a,b) (a+b+MOD)%MOD
21 #define mns(a,b) (a-b+MOD)%MOD
22 #define mul(a,b) (1LL*(a)*(b))%MOD
23 using namespace std;
24 inline int read()
25 {
26     int x=0,f=1;char ch=getchar();
27     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
28     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
29     return x*f;
30 }
31 int n,m,s,t;
32 struct Dinic
33 {
34     int fst[MAXN],nxt[MAXN<<2],to[MAXN<<2],val[MAXN<<2],cnt;
35     int S,T,vis[MAXN],tot,cur[MAXN],q[MAXN],l,r,dis[MAXN];
36     Dinic(){memset(fst,0,sizeof(fst));cnt=1;}
37     void add(int u,int v,int w) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;} 
38     void ins(int u,int v,int w) {add(u,v,w);add(v,u,0);}
39     int bfs()
40     {
41         q[l=r=1]=T,vis[T]=++tot,dis[T]=0;int x;
42         while(l<=r)
43         {
44             x=q[l++];cur[x]=fst[x];ren if(vis[to[i]]!=tot&&val[i^1])
45                 vis[to[i]]=tot,dis[to[i]]=dis[x]+1,q[++r]=to[i];
46         }
47         return vis[S]==tot;
48     }
49     int dfs(int x,int a)
50     {
51         if(x==T||!a) return a;int f,flw=0;
52         for(int& i=cur[x];i&&a;i=nxt[i]) 
53             if(val[i]&&dis[to[i]]==dis[x]-1&&(f=dfs(to[i],min(a,val[i]))))
54                 val[i]-=f,val[i^1]+=f,flw+=f,a-=f;return flw;
55     }
56     int solve(int s,int t,int res=0)
57         {S=s,T=t;while(bfs()) res+=dfs(S,inf);return res;}
58 }D;
59 int main()
60 {
61     n=read(),m=read(),s=0,t=n+m+1;int a,b;rep(i,1,m)
62         {a=read()+1,b=read()+1;D.ins(a,i+n,1);D.ins(b,i+n,1);}
63     rep(i,1,n) D.ins(s,i,1);
64     rep(i,1,m+1) {D.ins(i+n,t,1);if(!D.solve(s,t)) return printf("%d
",i-1),0;}
65 }
bzoj 1191 代码(与此题只是数据范围区别

然后发现了奇妙的并查集做法

对每个装备的两个值连边,若形成一个$x$个点的树,则我们可以选走$x-1$个点,留下最大的那个

若成环,则都可以取。这样我们并查集合并即可,合并时找出最大的不行变成可以的

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<cmath>
 6 #include<algorithm>
 7 #include<queue>
 8 #include<vector>
 9 #include<map>
10 #include<set>
11 #define ll long long
12 #define db double
13 #define inf 2139062143
14 #define MAXN 1001000
15 #define MOD 1000000007
16 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i)
17 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i)
18 #define ren for(register int i=fst[x];i;i=nxt[i])
19 #define pb(i,x) vec[i].push_back(x)
20 #define pls(a,b) (a+b+MOD)%MOD
21 #define mns(a,b) (a-b+MOD)%MOD
22 #define mul(a,b) (1LL*(a)*(b))%MOD
23 using namespace std;
24 inline int read()
25 {
26     int x=0,f=1;char ch=getchar();
27     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
28     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
29     return x*f;
30 }
31 int n,m,fa[MAXN],ok[MAXN];
32 int find(int x) {return x==fa[x]?x:fa[x]=find(fa[x]);}
33 int main()
34 {
35     n=read(),m=10000;int a,b;rep(i,1,m) fa[i]=i;rep(i,1,n)
36     {
37         a=find(read()),b=find(read());if(a==b) {ok[a]=1;continue;}
38         if(a>b) swap(a,b);ok[!ok[a]?a:b]=1,fa[a]=b;
39     }rep(i,1,m+1) if(!ok[i]) return printf("%d
",i-1),0;
40 }
View Code
原文地址:https://www.cnblogs.com/yyc-jack-0920/p/10648429.html