解题报告 之 SOJ4429 Frog's Dice

解题报告 之 SOJ 4429 Frog's Dice


The Problem

frog has many dices:)
Each dice has six surfaces and there is a lowercase letter on each surfaces.
Now, frog want to put these dices in a row so that the letters on the upper faces could form a certain word.
She can put these dices in any order but each dice can only be used once.
Please tell frog whether she could make that thing happen.?

Input

The first line of input is the number of test case.

Then for each case:
The first line is a number n(1 <= n <= 1000), indicating the number of dices.
Then there are n lines, each line has six lowercase letters(separated by space), indicating the letters on a dice.
The last line has n lowercase letters, indicating frog's special word.


Output

For each case, print one line:
If frog can get her special word, print "Cong, frog!"(without quotation);
else print "Sorry, frog."

Example Input

2
3
s c u a c m
a b c d e f
a b c d e f
scu
4
a e c f a c
d z b g f a
p r j a a a
h e t g o a
frog

Example Output

Sorry, frog.
Cong, frog!

题目大意:Frog神有n个骰子,每个骰子每一面分别有一个字母,然后给你一个字符串,问你能不能用这些骰子拼出这个字符串,每个骰子使用小于等于1次。

分析:明显的二分图匹配,于是乎解决办法就是,设立n个骰子节点,26个字母节点,将超级源点与所有骰子节点连接,负载为INF。将第i个骰子与它每一面对应的字母连上一条负载为1的边。然后数一下字符串里每种字母出现了k次,就在对应的字母节点连一条负载为k的边到超级汇点。

最后看从超级源点到超级汇点的最大流是否==字符串长度l,如果等于则可以组成。那么就上代码了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<string>

using namespace std;

const int MAXN = 1510;
const int MAXM = 200010;
const int INF = 0x3f3f3f3f;

struct Edge
{
    int to, next;
    int cap;
};

Edge edge[MAXM];

int n;
int cnt, src, des;
//cnt表示一共有几条边
int head[MAXN];
//head[i]表示节点i的第一条边的编号
int level[MAXN];
int times[26];

void addedge(int from, int to, int cap)
{
    edge[cnt].to = to;
    edge[cnt].cap = cap;
    edge[cnt].next = head[from];
    head[from] = cnt++;

    edge[cnt].to = from;
    edge[cnt].cap = 0;
    edge[cnt].next = head[to];
    head[to] = cnt++;
}

int bfs()
{
    queue<int> q;
    while (!q.empty())
        q.pop();
    memset(level, -1, sizeof(level));
    level[src] = 0; //源点的深度为0
    q.push(src);

    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        for (int i = head[u]; i != -1; i = edge[i].next)
        {
            int v = edge[i].to;
            if (edge[i].cap > 0 && level[v] == -1) //该边未访问过且该边有流量
            {
                level[v] = level[u] + 1;
                q.push(v);
            }
        }
    }
    return level[des] != -1; //返回是否还存在连通路
}

int dfs(int u, int f)
{
    if (u == des)
        return f;
    int tem;
    for (int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].to;
        if (edge[i].cap > 0 && level[v] == level[u] + 1)
        {
            tem = dfs(v, min(f, edge[i].cap));
            if (tem > 0)
            {
                edge[i].cap -= tem;
                edge[i ^ 1].cap += tem; //更新边与反向边的流量
                return tem;
            }
        }
    }
    level[u] = -1; //表示已经走过该点
    return 0;
}

int Dinic()
{
    int ans = 0, tem;
    while (bfs())//如果还存在连通路
    {
        while (tem = dfs(src, INF)) //一直试图寻找增广路
        {
            ans += tem;
        }
    }
    return ans;
}

int main()
{

    int kase;
    scanf("%d", &kase);
    while (kase--)
    {

        char ch;
        scanf("%d", &n);

        cnt = 0;
        memset(head, -1, sizeof(head));
        memset(times, 0, sizeof(times));
        int f, d;
        src = n+26, des = src+1;
        for (int i = 0; i < n; i++)
        {
            addedge(src, i, 1);
        }

        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < 6; j++)
            {
                cin >> ch;
                int num = ch - 'a';
                addedge(i, n+num, 1);
            }
        }
        
        string str;
        cin >> str;
        int l = str.length();
        for (int i = 0; i < l; i++)
        {
            times[str[i] - 'a']++;
        }

        for (int i = 0; i < 26; i++)
        {
            if(times[i])
                addedge(n + i, des, times[i]);
        }
        if (str.length() == Dinic())
            cout << "Cong, frog!" << endl;
        else
            cout << "Sorry, frog." << endl;

    }
    return 0;
}

就是这样,反正校赛还是靠大大~~


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值