洛谷P1640 SCOI2010 连续攻击游戏 (并查集/匹配)

本题介绍两种做法;

1 并查集

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=1000005;
 4 int fa[N],n;
 5 bool vis[N];
 6  
 7 int getf(int a){
 8     if(fa[a]==a) return a;
 9     else return fa[a]=getf(fa[a]);
10 }
11  
12 void mg(int a,int b){
13     int af=getf(a);
14     int bf=getf(b);
15     if(af==bf) vis[af]=true;
16     else{
17         if(af<bf) swap(af,bf);
18         vis[bf]=true;
19         fa[bf]=af;
20     }
21 }
22  
23 int main()
24 {
25     memset(vis,false,sizeof(vis));
26     cin>>n;
27     for(int i=1;i<=n+1;i++) fa[i]=i;
28     for(int i=1;i<=n;i++){
29         int a,b;
30         cin>>a>>b;
31         mg(a,b);
32     }
33     for(int i=1;i<=n+1;i++){
34         if(!vis[i]){
35             cout<<i-1;
36             break;
37         }
38     }
39     return 0;
40 }

2 更普遍的做法,也是更容易想到的,用二分图匹配来做,

将每个武器的两个属性分别向武器连边,因为是连续攻击(即从1开始),我们从1开始匹配,直到不能匹配为止,此时就得到答案。

代码中T表示时间戳,代替了匈牙利算法每次的memset(vis)。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=1000005;
 4 int adj[N],lk[N],id[N];
 5 int to[2*N],nex[2*N];
 6 int T,tot;
 7  
 8 int read() 
 9 { 
10     int a=0,f=1; char c=getchar(); 
11     while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();} 
12     while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();} 
13     return a*f; 
14 } 
15  
16 void ins(int x,int y){
17     nex[++tot]=adj[x];
18     adj[x]=tot;
19     to[tot]=y;
20 }
21  
22 bool mt(int x){
23     for(int i=adj[x];i;i=nex[i]){
24         int v=to[i];
25         if(id[v]==T) continue;
26         id[v]=T;
27         if(!lk[v]||mt(lk[v])){
28             lk[v]=x;
29             return 1;
30         }
31     }
32     return 0;
33 }
34  
35 int main(){
36     int n=read(),i,x,y;
37     for(i=1;i<=n;i++) {
38         x=read();y=read();
39         ins(x,i);ins(y,i);
40     }
41     for(i=1;i<=10000;i++){
42         T++;
43         if(!mt(i)) break;
44     }
45     cout<<i-1;
46     return 0;
47 }

 

posted @ 2022-04-04 15:18  YHXo  阅读(39)  评论(0编辑  收藏  举报