川大oj 4429

本文介绍了一种使用网络流算法解决特定骰子组合问题的方法。问题要求判断是否能通过给定的字母骰子拼出指定字符串。采用二分图匹配思路遇到超时问题后,转而利用网络流进行优化求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:给你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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值