点击打开链接
题意:给n个串,是0则不可以反转,是1可以反转,问能否头尾相连的将所有串连在一起
思路:做法是先判断一下图是否联通,用并查集判断就行,然后是先将图变成欧拉回路,那么只能有两种情况,没有奇度顶点,或者有两个奇度顶点,一个cnt大于0,一个cnt小于0,cnt代表的是一个点的入度减去出度的值,只有这两种情况才可以形成一个欧拉回路,但是如果是两个奇度顶点的话,需要将大于0的顶点连向小于0的顶点,这样就可以变成一个欧拉回路了,然后处理的是图中的无向边,先将无向边随意转化成有向边,如1-->4那么网络流中建图建一条4-->1权值为2的边,一会说为什么权值为2,然后处理的是对于这些入度与出度不平衡的点,写着感觉与有上下界的网络流特别向,就套用了过来,如果cnt大于0,则源点与其相连权值为cnt,然后cnt小于0的与汇点相连,权值为-cnt,因为是这么连的,解释一下上边的权值为2的原因,1-->4 代表的1是出度,4是入度,而网络流建的图是4-->1代表的是4为出度,1为入度,两相比较的话是少了2,而不是1,太抽象了~~,看代码把
#include <queue> #include <vector> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; typedef unsigned long long ull; const int inf=0x3f3f3f3f; const ll INF=0x3f3f3f3f3f3f3f3fll; const int maxn=2010; struct edge{ int to,cap,rev; edge(int a,int b,int c){to=a;cap=b;rev=c;} }; vector<edge>G[maxn]; int level[maxn],iter[maxn]; void add_edge(int from,int to,int cap){ G[from].push_back(edge(to,cap,G[to].size())); G[to].push_back(edge(from,0,G[from].size()-1)); } void bfs(int s){ memset(level,-1,sizeof(level)); queue<int>que;level[s]=0; que.push(s); while(!que.empty()){ int v=que.front();que.pop(); for(unsigned int i=0;i<G[v].size();i++){ edge &e=G[v][i]; if(e.cap>0&&level[e.to]<0){ level[e.to]=level[v]+1; que.push(e.to); } } } } int dfs(int v,int t,int f){ if(v==t) return f; for(int &i=iter[v];i<G[v].size();i++){ edge &e=G[v][i]; if(e.cap>0&&level[v]<level[e.to]){ int d=dfs(e.to,t,min(f,e.cap)); if(d>0){ e.cap-=d; G[e.to][e.rev].cap+=d; return d; } } } return 0; } int max_flow(int s,int t){ int flow=0; while(1){ bfs(s); if(level[t]<0) return flow; memset(iter,0,sizeof(iter)); int f; while((f=dfs(s,t,inf))>0) flow+=f; } } int f[30],vis[30],cnt[30];//cnt代表入度减去出度的值 char str[maxn][50]; int find1(int x){ if(x!=f[x]) f[x]=find1(f[x]); return f[x]; } void unite(int a,int b){ int aa=find1(a); int bb=find1(b); if(aa==bb) return ; f[aa]=bb; } int main(){ int T,cas=1,n,type; scanf("%d",&T); while(T--){ scanf("%d",&n); for(int i=0;i<maxn;i++) G[i].clear(); for(int i=0;i<30;i++) vis[i]=0,f[i]=i,cnt[i]=0; for(int i=0;i<n;i++){ scanf("%s%d",str[i],&type); int a=str[i][0]-'a'+1; int len=strlen(str[i]); int b=str[i][len-1]-'a'+1; cnt[a]--;cnt[b]++; vis[a]=1;vis[b]=1; if(type) add_edge(b,a,2); unite(a,b); } int sum=0; for(int i=1;i<=26;i++) if(vis[i]&&f[i]==i) sum++; printf("Case %d: ",cas++); if(sum>1){ printf("Poor boy!\n");continue; } int sum1=0,t1,t2,sum2=0; for(int i=1;i<=26;i++){ if(cnt[i]>0&&cnt[i]%2==1){ sum1++;t1=i; }else if(cnt[i]<0&&-cnt[i]%2==1){ sum2++;t2=i; } } if(sum1==1&&sum2==1) add_edge(t1,t2,1); else if(sum1==0&&sum2==0){} else{ printf("Poor boy!\n");continue; } sum=0; for(int i=1;i<=26;i++){ if(cnt[i]>0){ sum+=cnt[i];add_edge(0,i,cnt[i]); }else if(cnt[i]<0){ add_edge(i,27,-cnt[i]); } } int ans=max_flow(0,27); if(sum==ans) printf("Well done!\n"); else printf("Poor boy!\n"); } return 0; }