JOJ 2727:GRE(ハイブリッドオーラロード)
7599 ワード
アルゴリズムは基本的にSightseeing tourと同じであるが,判定図の連通性に注意し,かつ判定条件を緩和し,2度が奇抜な点がある場合には,1辺を加えて回路を構成する.
一般的なEKアルゴリズム
ダゴのテンプレートが改良された後、JOJ一を走って、へへへ
一般的なEKアルゴリズム
#include <cstdio>
#include <string.h>
#include <string>
#include <map>
#include <iostream>
#define min(a,b) ((a)>(b))?(b):(a)
using namespace std ;
const int maxn=30;
const int Inf=0x7fffffff;
int cap[maxn][maxn],flow[maxn][maxn],p[maxn],minflow[maxn],q[maxn];
int deg[maxn];
int n,m,junc;
int I=0;
bool vis[maxn];
int maxflow(int s , int t)
{
int f=0,u,v,rear,head;
memset(flow , 0 , sizeof(flow));
while (true)
{
memset(minflow , 0 , sizeof(minflow));
minflow[s]=Inf;
head=0;
rear=1;
q[head]=s;
while (rear>head)
{
u=q[head];head++;
for (v=0 ; v<=t ; ++v)
{
if(!minflow[v] && cap[u][v]>flow[u][v])
{
p[v]=u;
q[rear]=v;rear++;
minflow[v]=min(minflow[u],cap[u][v]-flow[u][v]);
}
}
}
//printf("mint=%d
",minflow[t]);
if(!minflow[t])break;
for (u=t ; u!=s ; u=p[u])
{
flow[u][p[u]]-=minflow[t];
flow[p[u]][u]+=minflow[t];
}
f+=minflow[t];
}
return f;
}
int find (int x)
{
return p[x]<0?x:p[x]=find(p[x]);
}
void merge (int a , int b)
{
int x=find(a);
int y=find(b);
int tmp;
if(x!=y)
{
tmp=p[x]+p[y];
(p[x]>p[y])?(p[x]=y,p[y]=tmp):(p[y]=x,p[x]=tmp);
junc++;
}
}
int main ()
{
int cas,i,j,u,v,d,sum,point;
const int s=26;
const int t=27;
string str;
//map<string,int>mapstr;
//freopen ("in.txt","r",stdin);
//freopen ("out.txt","w",stdout);
scanf("%d",&cas);
while (cas--)
{
memset (cap , 0 , sizeof(cap));
memset (deg , 0 , sizeof(deg));
memset (vis , 0 , sizeof(vis));
//mapstr.clear();
point=sum=0;
scanf("%d",&m);
for (i=0 ; i<26 ; ++i)
p[i]=-1;
junc=1;
for (i=0 ; i<m ; ++i)
{
cin>>str>>d;
//printf("map=%d
",mapstr[str]);
//if(mapstr[str]==0)
{
int len=str.size();
u=str[0]-'a';v=str[len-1]-'a';
vis[u]=1; vis[v]=1;
merge(u,v);
if(v!=u)
deg[v]++,deg[u]--;
if(d)cap[u][v]+=1;
//mapstr[str]=i+1;
}
//printf("u=%d v=%d
",u,v);
}
bool flag=true;
for (i=0 ; i<26 ; ++i)
if(vis[i])point++;
if(point!=junc)flag=false;
int odd_d=0,start=28,end=28;
for (i=0 ; i<26 ; ++i)
{
if(deg[i]&1)
{
odd_d++;
if(odd_d==1)start=i,deg[i]--;
if(odd_d==2)end=i,deg[i]++;
//printf("%d %d
",i,odd_d);
}
if(odd_d>2)flag=false;
if(!flag)break;
}
if(flag)
{
if(odd_d==2)
cap[start][end]+=1;
for (i=0 ; i<26 ; ++i)
{
//printf("%d ",deg[i]);
deg[i]>>=1;
if(deg[i]>0)cap[i][t]=deg[i],sum+=deg[i];
if(deg[i]<0)cap[s][i]=-deg[i];
}
int ans=maxflow(s,t);
//printf("
%d %d
%d %d
",ans,sum,start,end);
printf("%d %d
",junc,point);
if(ans==sum)printf("Case %d: Well done!
",++I);
else printf("Case %d: Poor boy!
",++I);
}
else printf("Case %d: Poor boy!
",++I);
}
return 0;
}
ダゴのテンプレートが改良された後、JOJ一を走って、へへへ
#include <cstdio>
#include <string.h>
#define min(a,b) ((a)>(b))?(b):(a)
using namespace std ;
const int maxn=28;
const int Inf=0x5fffffff;
int cap[maxn][maxn],dist[maxn],gap[maxn],fath[maxn];
int deg[maxn];
int n=27,m,junc;
int I=0;
const int source=0;// 0, 26
const int sink=27;
bool vis[maxn];
int dfs (int p , int limit=Inf)
{
if(p==n)return limit;
for (int i=0 ; i<=n ; ++i)
{
if(dist[p]==dist[i]+1 && cap[p][i]>0)
{
int t=dfs(i,min(limit , cap[p][i]));
if(t<0)return t;//
if(t>0)//
{
cap[p][i]-=t;
cap[i][p]+=t;
return t;
}
}
}
int tmp=n+1 ;
for (int i=0 ; i<=n ; ++i)
if(cap[p][i]>0)
tmp=min(tmp,dist[i]+1);
//printf("dist[p]=%d dist0=%d tmp=%d
",dist[p],dist[0],tmp);
//printf("gap=");
//for (int i=0 ; i<n ; i++)printf("%d ",gap[i]);
//puts("");
if(--gap[dist[p]]==0 || dist[0]>n)return -1;//
++gap[dist[p]=tmp];
return 0;
}
int SAP()
{
gap[source]=n+1;
int f = 0 , t=0;
while (~(t=dfs(source))) f+=t;
//printf("%d
",t);
return f;
}
int find (int x)
{
return fath[x]<0?x:fath[x]=find(fath[x]);
}
void merge (int a , int b)
{
int x=find(a);
int y=find(b);
int tmp;
if(x!=y)
{
tmp=fath[x]+fath[y];
(fath[x]>fath[y])?(fath[x]=y,fath[y]=tmp):(fath[y]=x,fath[x]=tmp);
junc++;
}
}
int main ()
{
int cas,i,j,u,v,d,sum,point;
char str[25];
scanf("%d",&cas);
while (cas--)
{
memset (cap , 0 , sizeof(cap));
memset (deg , 0 , sizeof(deg));
memset (vis , 0 , sizeof(vis));
memset (dist , 0 , sizeof(dist));
memset (gap , 0 , sizeof(gap));
point=sum=0;
scanf("%d",&m);
for (i=1 ; i<=26 ; ++i)
fath[i]=-1;
junc=1;
for (i=0 ; i<m ; ++i)
{
scanf("%s%d",str,&d);
{
int len=strlen(str);
u=str[0]-'a'+1;v=str[len-1]-'a'+1;
vis[u]=1; vis[v]=1;
merge(u,v);
if(v!=u)
deg[v]++,deg[u]--;
if(d)cap[u][v]+=1;
}
//printf("u=%d v=%d
",u,v);
}
bool flag=true;
for (i=1 ; i<=26 ; ++i)
if(vis[i])point++;
if(point!=junc)flag=false;
int odd_d=0,start=28,end=28;
for (i=1 ; i<=26 ; ++i)
{
if(deg[i]&1)
{
odd_d++;
if(odd_d==1)start=i,deg[i]--;
if(odd_d==2)end=i,deg[i]++;
}
if(odd_d>2)flag=false;
if(!flag)break;
}
if(flag)
{
if(odd_d==2)
cap[start][end]++;
for (i=1 ; i<=26 ; ++i)
{
deg[i]>>=1;
if(deg[i]>0)cap[i][sink]=deg[i],sum+=deg[i];
if(deg[i]<0)cap[source][i]=-deg[i];
}
int ans=SAP();
if(ans==sum)printf("Case %d: Well done!
",++I);
else printf("Case %d: Poor boy!
",++I);
}
else printf("Case %d: Poor boy!
",++I);
}
return 0;
}