组队赛5:二分图+大模拟

URAL 1997 链接: http://acm.timus.ru/problem.aspx?space=1&num=1997

题意:进门和出门的人,如果有一组有全部的人都符合其在酒巴的时间>=a或者<=b,则为No reason,且输出入门出门的时间,否则为Liar。

这题太晕了……尼玛!把边的指向指错了,得先入门指向出门的才行,刚开始就这样一直WA,所以……

感觉这题收获太大了,以前没有全部理解二分图的后果耶,现在终于理解了。

二分图这题是单向边的,如果改为无向图的话,就是匹配*2了;

然后还有一点就是pre数组的使用,以前没有全部理解,哈哈,原来可以用pre数组用来输出当前点的前身结点,这以前怎么就不会呢,可能是以前没有遇到过吧!!!虽然以前知道这个是前向数组,即前向星,但是还没用来过输出呢,这题还是练得很好的……把自己的缺点都给暴露无疑了……

#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <list>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#define PI acos(-1.0)
#define mem(a,b) memset(a,b,sizeof(a))
#define sca(a) scanf("%d",&a)
#define pri(a) printf("%d\n",a)
#define lson i<<1,l,mid
#define rson i<<1|1,mid+1,r
#define MM 1000005
#define MN 1010
#define INF 55566677
#define eps 1e-7
using namespace std;
typedef long long ll;
int cnt=1,tem=1,s[MN],z[MN],vis[MN],pre[MN],Map[MN][MN];
int dfs(int u)
{
    for(int v=1;v<cnt;v++)
        if(!vis[v]&&Map[u][v])
        {
            vis[v]=1;
            if(!pre[v]||dfs(pre[v]))
            {
                pre[v]=u;
                return 1;
            }
        }
    return 0;
}
int solve()
{
    int ans=0,i;
    for(i=1;i<cnt;i++)
    {
        mem(vis,0);
        ans+=dfs(i);
    }
    return ans;
}
int main()
{
    int a,b,u,bb,n,i,j;
    scanf("%d%d%d",&a,&b,&n);
    for(i=0;i<n;i++)
    {
        scanf("%d%d",&u,&bb);
        if(bb) s[cnt++]=u;
        else z[tem++]=u;
    }
    if(cnt!=tem||n&1) {puts("Liar");return 0;}
    for(i=1;i<cnt;i++)
        for(j=1;j<cnt;j++)
        {
            int f=s[j]-z[i]; //原来是人先进去然后才出门
            //刚开始写s[i]-z[j]就错了,wa了多发改了才过,过!!!
            if(f>=0&&(f>=a||f<=b)) Map[i][j]=1;
        }
    if(solve()==cnt-1)
    {
        puts("No reason");
        for(i=1;i<cnt;i++)
            printf("%d %d\n",z[pre[i]],s[i]);
    }
    else puts("Liar");
    return 0;
}

你可能感兴趣的:(组队赛5:二分图+大模拟)