bzoj 1894 游戏
题目大意:
$n$个装备,每个装备有两个值,可以攻击该值对应的怪兽。每个装备最多用一次
每个怪兽被打一次之后就会死,每个怪兽可以被打当且仅当前面的都死了,求最多打多少个
思路:
很明显的二分图匹配,如果用$Dinic$的时候一条一条加入连向终点的边即可
但是为什么这道题我$TLE$了啊 垃圾Dinic要你有何用,我也不(wang)会(le)匈牙利啊
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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\n",i-1),0;} 65 }
然后发现了奇妙的并查集做法
对每个装备的两个值连边,若形成一个$x$个点的树,则我们可以选走$x-1$个点,留下最大的那个
若成环,则都可以取。这样我们并查集合并即可,合并时找出最大的不行变成可以的
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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\n",i-1),0; 40 }