您的位置:首页 > 理论基础 > 计算机网络

HDU 3472 网络流

2016-06-15 12:52 489 查看
点击打开链接

题意:给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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: