【CF1252L】Road Construction(基环树,最大流)

题意:给定一张n点n边无重边自环的无向图,刚开始每条边都没有被选择,每条边上有一个颜色集合,必须从中选择一种

有K个工人,每个工人有颜色a[i],需要把工人分配到与其颜色相同的边上

问是否能有一种使得n个点完全联通的方案,如果有则输出

n,K<=2000

思路:考虑n-1条边的树的弱化版,显然每条边都应该被选择,用颜色和边建图跑最大流即可

n点n边的基环树的情况下需要把环抠出来,设环的大小为size,两个端点至少有一个在环中的为A集合,其余为B集合

显然B集合中所有的边都需要被选取,A集合中至多只能选择size-1条

可以另外加源或者汇限制A集合的流量,也可以先加入B集合中的所有边,先跑最大流,判断是否小于n-size,因为A集合至多只有size-1的流量

两种方法都试过,都很快

我猜题解里写的应该就是用最大流跑的匹配,没听说过有能跑这个多重匹配的新算法

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 typedef long long ll;
  4 typedef unsigned int uint;
  5 typedef unsigned long long ull;
  6 typedef long double ld;
  7 typedef pair<int,int> PII;
  8 typedef pair<ll,ll> Pll;
  9 typedef vector<int> VI;
 10 typedef vector<PII> VII;
 11 typedef pair<ll,ll>P;
 12 #define N  200010
 13 #define M  1000000
 14 #define INF 1e9
 15 #define fi first
 16 #define se second
 17 #define MP make_pair
 18 #define pb push_back
 19 #define pi acos(-1)
 20 #define mem(a,b) memset(a,b,sizeof(a))
 21 #define rep(i,a,b) for(int i=(int)a;i<=(int)b;i++)
 22 #define per(i,a,b) for(int i=(int)a;i>=(int)b;i--)
 23 #define lowbit(x) x&(-x)
 24 #define Rand (rand()*(1<<16)+rand())
 25 #define id(x) ((x)<=B?(x):m-n/(x)+1)
 26 #define ls p<<1
 27 #define rs p<<1|1
 28 #define fors(i) for(auto i:e[x]) if(i!=p)
 29 
 30 const int MOD=1e9+7,inv2=(MOD+1)/2;
 31       double eps=1e-6;
 32       int dx[4]={-1,1,0,0};
 33       int dy[4]={0,0,-1,1};
 34 
 35 int head[N],vet[N],len[N],nxt[N],inq[N],inc[N],a[N],
 36     flag[N],vis[N],stk[N],dis[N],p[N],c[N],match[N],
 37     tot,top,s,S,T,T1;
 38 
 39 VI b[N],co[N];
 40 
 41 int read()
 42 {
 43    int v=0,f=1;
 44    char c=getchar();
 45    while(c<48||57<c) {if(c=='-') f=-1; c=getchar();}
 46    while(48<=c&&c<=57) v=(v<<3)+v+v+c-48,c=getchar();
 47    return v*f;
 48 }
 49 
 50 ll readll()
 51 {
 52    ll v=0,f=1;
 53    char c=getchar();
 54    while(c<48||57<c) {if(c=='-') f=-1; c=getchar();}
 55    while(48<=c&&c<=57) v=(v<<3)+v+v+c-48,c=getchar();
 56    return v*f;
 57 }
 58 
 59 void add(int a,int b)
 60 {
 61     nxt[++tot]=head[a];
 62     vet[tot]=b;
 63     head[a]=tot;
 64 }
 65 
 66 void Add(int a,int b,int c)
 67 {
 68     nxt[++tot]=head[a];
 69     vet[tot]=b;
 70     len[tot]=c;
 71     head[a]=tot;
 72 
 73     nxt[++tot]=head[b];
 74     vet[tot]=a;
 75     len[tot]=0;
 76     head[b]=tot;
 77 }
 78 
 79 void findc(int u,int fa)
 80 {
 81     stk[++top]=u;
 82     inq[u]=vis[u]=1;
 83     int e=head[u];
 84     while(e)
 85     {
 86         int v=vet[e];
 87         if(!vis[v]) findc(v,u);
 88          else if(v!=fa&&inq[v])
 89          {
 90              int s=1,t=top;
 91              while(1)
 92              {
 93                  t--;
 94                  s++;
 95                  if(stk[t]==v) break;
 96              }
 97              if(s>=3)
 98              {
 99                 t=top;
100                 while(1)
101                 {
102                     inc[stk[t]]=1;
103                     t--;
104                     if(stk[t]==v){inc[v]=1; break;}
105                 }
106 
107              }
108          }
109         e=nxt[e];
110     }
111     inq[stk[top]]=0;
112     top--;
113 }
114 
115 int bfs()
116 {
117     queue<int> q;
118     rep(i,1,s) dis[i]=-1;
119     q.push(S),dis[S]=0;
120     while(!q.empty())
121     {
122         int u=q.front();
123         q.pop();
124         int e=head[u];
125         while(e)
126         {
127             int v=vet[e];
128             if(len[e]&&dis[v]==-1)
129             {
130                 dis[v]=dis[u]+1;
131                 q.push(v);
132             }
133             e=nxt[e];
134         }
135     }
136     return dis[T]!=-1;
137 }
138 
139 int dfs(int u,int aug)
140 {
141     if(u==T) return aug;
142     int e=head[u],val=0,flow=0;
143     while(e)
144     {
145         int v=vet[e];
146         if(len[e]&&dis[v]==dis[u]+1)
147         {
148             int t=dfs(v,min(len[e],aug));
149             if(!t)
150             {
151                 e=nxt[e];
152                 continue;
153             }
154             flow+=t;
155             aug-=t;
156             len[e]-=t;
157             len[e^1]+=t;
158             if(!aug) break;
159         }
160         e=nxt[e];
161     }
162     if(!flow) dis[u]=-1;
163     return flow;
164 }
165 
166 int main()
167 {
168     int n=read(),K=read();
169     int m=0;
170     rep(i,1,n)
171     {
172         p[i]=read();
173         int x=read();
174         while(x--)
175         {
176             int y=read();
177             b[i].pb(y);
178             c[++m]=y;
179         }
180     }
181     rep(i,1,K)
182     {
183         a[i]=read();
184         c[++m]=a[i];
185     }
186     sort(c+1,c+m+1);
187     int k=unique(c+1,c+m+1)-c-1;
188     rep(i,1,n)
189      for(int j=0;j<b[i].size();j++) b[i][j]=lower_bound(c+1,c+k+1,b[i][j])-c;
190 
191 
192     rep(i,1,k) co[i].clear();
193     rep(i,1,K)
194     {
195         a[i]=lower_bound(c+1,c+k+1,a[i])-c;
196         co[a[i]].pb(i);
197     }
198 
199     tot=0;
200     rep(i,1,n)
201     {
202         add(i,p[i]);
203         add(p[i],i);
204     }
205     findc(1,0);
206     s=k+n,S=++s,T=++s;
207     rep(i,1,s) head[i]=0;
208     tot=1;
209     int sz=0;
210     rep(i,1,k) Add(S,i,co[i].size());
211     rep(i,1,n)
212      for(int j=0;j<b[i].size();j++) Add(b[i][j],i+k,1);
213     rep(i,1,n)
214      if(inc[i]==0||inc[p[i]]==0) Add(i+k,T,1);
215       else sz++;
216     int ans=0;
217     while(bfs()) ans+=dfs(S,INF);
218     if(ans<(n-1-(sz-1)))
219     {
220         printf("-1
");
221         return 0;
222     }
223     rep(i,1,n)
224      if(inc[i]&&inc[p[i]]) Add(i+k,T,1);
225     while(bfs()) ans+=dfs(S,INF);
226     if(ans<n-1) printf("-1
");
227      else
228      {
229         rep(i,1,n) flag[i]=0;
230         rep(i,1,k)
231         {
232             int e=head[i],j=0;
233             while(e)
234             {
235                 int v=vet[e];
236                 if(v>=k+1&&v<=k+n&&flag[v-k]==0&&!len[e])
237                 {
238                     j++;
239                     if(j>(int)co[i].size()) break;
240                     int t=co[i][j-1];
241                     match[t]=v-k;
242                     flag[v-k]=1;
243                 }
244                 e=nxt[e];
245             }
246         }
247         rep(i,1,K) printf("%d %d
",match[i],p[match[i]]);
248      }
249 
250 
251     return 0;
252 }
原文地址:https://www.cnblogs.com/myx12345/p/11808160.html