百度之星复赛Valley Numer II

Valley Numer II
Problem Description
众所周知,度度熊非常喜欢图。
它最近发现了图中也是可以出现 valley —— 山谷的,像下面这张图。
为了形成山谷,首先要将一个图的顶点标记为高点或者低点。标记完成后如果一个顶点三元组X, Y, Z>中,X和Y之间有边,Y与Z之间也有边,同时X和Z是高点,Y是低点,那么它们就构成一个valley。
度度熊想知道一个无向图中最多可以构成多少个valley,一个顶点最多只能出现在一个valley中。
Input
第一行为T,表示输入数据组数。
每组数据的第一行包含三个整数N,M,K,分别表示顶点个数,边的个数,标记为高点的顶点个数。
接着的M行,每行包含两个两个整数Xi,Yi,表示一条无向边。
最后一行包含K个整数Vi,表示这些点被标记为高点,其他点则都为低点。
● 1≤T≤20
● 1≤N≤30
● 1≤M≤N*(N-1)/2
● 0≤K≤min(N,15)
● 1≤Xi, Yi≤N, Xi!=Yi
● 1≤Vi≤N
Output
对每组数据输出最多能构成的valley数目。
Sample Input
3
3 2 2
1 2
1 3
2 3
3 2 2
1 2
1 3
1 2
7 6 5
1 2
1 3
1 4
2 3
2 6
2 7
3 4 5 6 7
Sample Output
1
0
2

这题的话,当时打比赛的时候有一个十分错误的做法:
就是把匈牙利算法直接上,大概就是拆下点,然后跑一下。。。
一开始觉得很对啊,于是就很开心地打了
于是我就WA了。。
这里写图片描述
经过很久打对拍【在此我也浪费了很多时间静态查错】,终于发现了上面的数据。。
左边是高点。。。右边是低点
可以发现,要是直接上的话是只能找到1的。。
于是最后10min就觉得是网络流,于是激动地码网络流,当然不大行
那怎么做呢?
我们还是考虑匈牙利。。
我们发现低点或者高点的个数总有一个是比较小的。。换句话说,答案不大
所以我们可以暴力枚举一下,那些低点需要,然后用匈牙利来验证就没有问题啦!
当然,我觉得,要是你先枚举完在验证,是很有超时的可能性的,具体我也没试过
但是,要是你一边枚举一边验证,状态数就会少很多,就可以过了。。
ORZ cys

#include<cstdio>
#include<cstring>
const int N=35*2;
const int M=N*(N-1);
int n,m,k;
struct qq
{
    int x,y,last;
}s[M];int num,last[N];
qq e[M];int num1,last1[N];
void init1 (int x,int y)
{
    num1++;
    e[num1].x=x;e[num1].y=y;
    e[num1].last=last1[x];
    last1[x]=num1;
}
bool shen[N];//这个点是不是高点
void init (int x,int y)
{
    num++;
    s[num].x=x;s[num].y=y;
    s[num].last=last[x];
    last[x]=num;
}
int ff[N],f[N];//配对关系 
bool vis[N];
bool lalal (int x)//他是否可以配对成功 
{
    for (int u=last[x];u!=-1;u=s[u].last)
    {
        int y=s[u].y;
        if (vis[y]==true) continue;
        vis[y]=true;
        if (f[y]==-1||lalal(f[y])==true)
        {
            f[y]=x;ff[x]=y;
            return true;
        }
    }
    return false;
}
void solve ()
{
    memset(f,-1,sizeof(f));
    int ans=0;
    for (int u=1;u<=n;u++)
        if (!shen[u])//这是一个低点 
        {
            memset(vis,false,sizeof(vis));
            if (lalal(u)==true)//可以配对成功 
            {
                memset(vis,false,sizeof(vis));
                if (lalal(u+n)==true)
                    ans++;
                else
                    f[ff[u]]=-1;
            }
        }
    printf("%d\n",ans);
}
int ans=0;
int mymax (int x,int y)
{
    return x>y?x:y;
}
void dfs (int x,int y)
{
    if (x>n) 
    {
        ans=mymax(ans,y);
        return ;
    }
    if (shen[x]) dfs(x+1,y);
    else
    {
        dfs(x+1,y);//这个我不要
        memset(vis,false,sizeof(vis));
        if (lalal(x)==true)//可以配对成功 
        {
            memset(vis,false,sizeof(vis));
            if (lalal(x+n)==true)
            {
                dfs(x+1,y+1);
                f[ff[x]]=-1;
                f[ff[x+n]]=-1;
            }
            else
                f[ff[x]]=-1;
        }
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        memset(shen,false,sizeof(shen));
        num1=0;memset(last1,-1,sizeof(last1));
        num=0;memset(last,-1,sizeof(last));
        scanf("%d%d%d",&n,&m,&k);
        for (int u=1;u<=m;u++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            init1(x,y);init1(y,x);
        }
        for (int u=1;u<=k;u++)
        {
            int x;
            scanf("%d",&x);
            shen[x]=true;
        }
        for (int u=1;u<=n;u++)
            if (!shen[u])//这是一个低点 
                for (int i=last1[u];i!=-1;i=e[i].last)
                {
                    int y=e[i].y;
                    if (shen[y])//只有这个是有用的 
                    {
                        init(u,y);
                        init(u+n,y);
                    }
                }
            ans=0;
        memset(f,-1,sizeof(f));
        dfs(1,0);
        printf("%d\n",ans);
        //solve();
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值