题目链接:https://ac.nowcoder.com/acm/contest/1114/D;
思路:骰子总共只有C( 9,6 ) 就是84种,建立超级源点,源点和每个骰子连边,流量为同一种类骰子的个数,每个骰子和1,2,3……8,9连边,最后把询问序列和1,2,3……8,9连边,跑网络流。
代码有解释:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=200;
struct node
{
int v,ne,w;
}q[N*N];
int dis[N],cur[N],f[N];
int s,t,e;
void add_op(int a,int b,int c)
{
q[e].v=b;
q[e].w=c;
q[e].ne=f[a];
f[a]=e++;
}
void add(int a,int b,int c)
{
add_op(a,b,c);
add_op(b,a,0);
}
int dinic_dfs(int now,int maxx)
{
if(now==t) return maxx;
int res=0;
for(int &i=cur[now];i!=-1;i=q[i].ne)
{
int v=q[i].v,w=q[i].w;
if(w&&dis[v]==dis[now]+1)
{
int mini=min(w,maxx-res);
w=dinic_dfs(v,mini);
q[i].w-=w;
q[i^1].w+=w;
res+=w;
if(res==maxx) return res;
}
}
return res;
}
bool dinic_bfs()
{
queue<int>que;
memset(dis,0,sizeof(dis));
dis[s]=1;
que.push(s);
while(!que.empty())
{
int u=que.front();
que.pop();
if(u==t) return true;
for(int i=f[u];i!=-1;i=q[i].ne)
{
int v=q[i].v;
if(dis[v]==0&&q[i].w)
{
dis[v]=dis[u]+1;
que.push(v);
}
}
}
return false;
}
int dinic()//网络流算法
{
int res=0;
while(dinic_bfs())
{
for(int i=s;i<=t;i++) cur[i]=f[i];
res+=dinic_dfs(s,inf);
}
return res;
}
map<string,int>mp;//用容器来存每种骰子的个数
map<string,int>::iterator it;
void build_edge()//注意网络流算法会改变流量值,所以每次询问都要重新渐变
{
memset(f,-1,sizeof(f));
e=0;
int cnt=0,k=mp.size();
for(it=mp.begin();it!=mp.end();it++)
{
++cnt;
int x=it->second;
add(0,cnt,x);//源点和骰子建边
for(int i=0;i<6;i++)
add(cnt,k+it->first[i]-'0',x);//骰子和数字建边
}
}
int main()
{
int n,q;
string str;
scanf("%d %d",&n,&q);
for(int i=1;i<=n;i++)
{
cin>>str;
sort(str.begin(),str.end());//注意排一下序
mp[str]++;
}
s=0;
int k=mp.size(),num[11];
for(int i=1;i<=q;i++)
{
int sum=0;
memset(num,0,sizeof(num));
cin>>str;
for(int j=0;j<str.size();j++)
num[str[j]-'0']++;
t=k+10;
build_edge();
for(int j=1;j<=9;j++)
{
sum+=num[j];
add(k+j,t,num[j]);
}
int ans=dinic();
if(ans==sum) printf("dyf\n");
else printf("zzk\n");
}
return 0;
}