3 6 aloha 0 arachnid 0 dog 0 gopher 0 tar 1 tiger 0 3 thee 1 earn 0 nothing 0 2 pat 1 acm 0
Case 1: Well done! Case 2: Well done! Case 3: Poor boy!HintIn the first case, the word “tar” is still meaningful when reversed, and love8909 can make a list as “aloha-arachnid-dog-gopher-rat-tiger”. In the second case, the word “thee” is still meaningful when reversed, and love8909 can make a list as “thee-earn-nothing”. In the third case, no lists can be created.
解:这题是混合路的欧拉路径问题。
1.首先判断图的连通性,若不连通,无解。
2设立源点s和汇点t,若某点i入度<出度,连边(s,i,-deg[i]/2),若入度>出度,连边(i,t,deg[i]/2);对于任意定向的无向边(i,j,1)。
3.若有两个度数为奇数的点,假设存在欧拉路径,添加一条容量为1的边,构成欧拉回路,不影响结果。若全为偶数,直接最大流。找到出入度为奇数的两个点,一个起点,out[起点]++,一个终点,in[终点]++,从起点向起点连容量为1边的即可。
4若从S发出的边全部满流,证明存在欧拉回路(路径),否则不存在。
ps:若要求输出路径,将网络中有(无)流量的边反向,加上原图的有向边,用套圈算法即可。
#include <map> #include <set> #include <stack> #include <queue> #include <cmath> #include <ctime> #include <vector> #include <cstdio> #include <cctype> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; #define INF 0x3f3f3f3f #define inf -0x3f3f3f3f #define lson k<<1, L, mid #define rson k<<1|1, mid+1, R #define mem0(a) memset(a,0,sizeof(a)) #define mem1(a) memset(a,-1,sizeof(a)) #define mem(a, b) memset(a, b, sizeof(a)) typedef long long ll; const int maxn=1000 + 10; int in[maxn],out[maxn]; int f[30]; struct Edge{ int from,to,cap,flow; Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){} }; struct Dinic{ int n,m,s,t; //结点数,边数(包括反相弧),源点编号和汇点编号 vector<Edge>edges; //边表,edges[e]和edges[e^1]互为反相弧 vector<int>G[maxn]; //邻接表,G[i][j]表示结点i的第j条边在e数组中的序号 bool vis[maxn]; //BFS使用 int d[maxn]; //从起点到i的距离 int cur[maxn]; //当前弧下标 void AddEdge(int from,int to,int cap){ edges.push_back(Edge(from,to,cap,0)); edges.push_back(Edge(to,from,0,0)); m=edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } void init(int n){ this->n=n; for(int i=0;i<n;i++) G[i].clear(); edges.clear(); } bool BFS(){ mem0(vis); queue<int>Q; Q.push(s); d[s]=0; vis[s]=1; while(!Q.empty()){ int x=Q.front(); Q.pop(); for(int i=0;i<G[x].size();i++){ //只考虑残量网络中的弧 Edge& e=edges[G[x][i]]; if(!vis[e.to]&&e.cap>e.flow){ vis[e.to]=1; d[e.to]=d[x]+1; Q.push(e.to); } } } return vis[t]; } int DFS(int x,int a){ if(x==t||a==0) return a; int flow=0,f; for(int& i=cur[x];i<G[x].size();i++){ Edge& e=edges[G[x][i]]; if(d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0){ e.flow+=f; edges[G[x][i]^1].flow-=f; flow+=f; a-=f; if(a==0) break; } } return flow; } void Maxflow(int s,int t){ this->s=s; this->t=t; int flow=0; while(BFS()){ mem0(cur); flow+=DFS(s,INF); } bool flag=true; for(int i=0;i<G[0].size();i++){ Edge& e=edges[G[0][i]]; if(e.cap>e.flow){ flag=false; break; } } if(!flag) printf("Poor boy!\n"); else printf("Well done!\n"); } }; int find(int x){ return x == f[x] ? x : find(f[x]); } Dinic solve; char s[100]; int main(){ int u,v,w; int n,m,_; scanf("%d",&_); for(int case1=1;case1<=_;case1++){ scanf("%d",&n); solve.init(n+3); //这里注意要稍微大一点 for(int i=1;i<=26;i++) f[i]=i; mem0(out); mem0(in); for(int i=0;i<n;i++){ scanf("%s%d",s,&w); u=s[0]-'a'+1,v=s[strlen(s)-1]-'a'+1; out[u]++; in[v]++; int x=find(u); int y=find(v); if(x!=y){ f[x]=y; } if(w==1){ solve.AddEdge(u,v,1); } } int num=0; for(int i=1;i<=26;i++) //是否连通 if(out[i]+in[i]!=0){ if(f[i]==i) num++; } if(num!=1){ printf("Case %d: Poor boy!\n",case1); continue; } int cnt=0,start,end1; for(int i=1;i<=26;i++){ if(out[i]+in[i]==0) continue; if((out[i]-in[i])&1){ if(cnt==0){ start=i; out[i]++; } else{ end1=i; in[i]++; solve.AddEdge(start,end1,1); } cnt++; } if(out[i]-in[i]>0) solve.AddEdge(0,i,(out[i]-in[i])/2); if(in[i]-out[i]>0) solve.AddEdge(i,n+1,(in[i]-out[i])/2); } if(cnt!=2&&cnt!=0){ printf("Case %d: Poor boy!\n",case1); continue; } printf("Case %d: ",case1); solve.Maxflow(0,n+1); } return 0; }