题意:给定一张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 }