題目大意:給你n個骰子,骰子每面是一個字母,最後給你一個串,讓你每個骰子只能用一次時,能否組合成所給的串
解題思路:比賽的時候我們想的建一個二分圖,跑二分匹配,這個思路是沒有錯的,但二分匹配跑超時了,自己就沒更加深入的思考,因爲自己覺得二分匹配時能夠跑過的,當時改的相當冒火。最後下來題解說二分匹配是能夠過的(自己的二分匹配太挫),自己用網絡流過的,建圖思想:將每個骰子與自己有的字母連起來,將給的串的字母與匯點連起來,起點與沒給骰子連起來,每個邊的容量都爲1,然後跑一次最大流即可,詳見代碼
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
#define mmax 30005
#define inf 99999999
char s[1005];
int used[2005][30];
struct node
{
int flow;
int en;
int next;
}E[mmax];
int p[mmax];
int num;
void init()
{
memset(p,-1,sizeof p);
num=0;
}
void add(int st,int en,int flow)
{
E[num].en=en;
E[num].flow=flow;
E[num].next=p[st];
p[st]=num++;
E[num].en=st;
E[num].flow=0;
E[num].next=p[en];
p[en]=num++;
}
bool vis[mmax];
int d[mmax];
int cur[mmax];
bool bfs(int st,int en)
{
memset(vis,0,sizeof vis);
d[st]=0;
vis[st]=1;
queue<int>q;
q.push(st);
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=p[x]; i+1; i=E[i].next)
{
int v=E[i].en;
if(!vis[v]&&E[i].flow)
{
vis[v]=1;
d[v]=d[x]+1;
q.push(v);
}
}
}
return vis[en];
}
int dfs(int st,int en,int flow)
{
if(st==en||flow==0)
return flow;
int f=0,dd;
for(int &i=cur[st]; i+1;i=E[i].next)
{
int v=E[i].en;
if(d[st]+1==d[v]&&(dd=dfs(v,en,min(flow,E[i].flow)))>0)
{
E[i].flow-=dd;
E[i^1].flow+=dd;
flow-=dd;
f+=dd;
if(flow==0)
break;
}
}
return f;
}
int dinic(int st,int en,int nn)
{
int flow=0;
while(bfs(st,en))
{
for(int i=0;i<=nn;i++)
cur[i]=p[i];
flow+=dfs(st,en,inf);
}
return flow;
}
int main()
{
int T;
scanf("%d",&T);
int n;
char c;
while(T--)
{
init();
scanf("%d",&n);
memset(used,0,sizeof(used));
for(int i=1;i<=n;i++)
{
for(int k=0;k<6;k++)
{
getchar();
c=getchar();
if(!used[i+26][c-'a'+1])
{
add(i+26,c-'a'+1,1);
used[i+26][c-'a'+1]=1;
//printf("%d->%d ",i+26,c-'a'+1);
}
}
//printf("\n");
add(0,i+26,1);
}
scanf("%s",s);
int len=strlen(s);
for(int i=0;i<len;i++)
{
add(s[i]-'a'+1,27+n,1);
//printf("->%d ",s[i]-'a'+1);
}
//printf("\n");
int ans=dinic(0,n+27,n+27);
//printf("%d\n",ans);
if(ans==len)
puts("Cong, frog!");
else
puts("Sorry, frog.");
}
return 0;
}