2017百度之星程序设计大赛

来源:互联网 发布:sai绘图软件中文版 编辑:程序博客网 时间:2024/06/07 02:32

Valley Numer II

                                                           Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
                                                                                           Total Submission(s): 415    Accepted Submission(s): 143


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
33 2 21 21 32 33 2 21 21 31 27 6 51 21 31 42 32 62 73 4 5 6 7
 

Sample Output
102

思路:状压DP。枚举最低点。

#include<bits/stdc++.h>using namespace std;int e[40][40];//保存边int a[40];//是否最高点int b[40];//记录最高点int d[2][(1<<15)+10];int main(){    int T,n,m,c;cin>>T;    while(T--)    {        memset(e,0,sizeof e);        memset(a,0,sizeof a);        scanf("%d%d%d",&n,&m,&c);        while(m--)        {            int x,y;            scanf("%d%d",&x,&y);            e[x][y]=e[y][x]=1;        }        for(int i=0;i<c;i++)        {            scanf("%d",&b[i]);            a[b[i]]=1;        }        memset(d,0,sizeof d);        int now=1,pre=0,ans=0; //二维滚动数组        for(int i=1;i<=n;i++)//枚举最低点        {            if(a[i])continue;            for(int tp=0;tp<(1<<c);tp++)d[now][tp]=d[pre][tp]; //把上一次的值更新过来            for(int tp=0;tp<(1<<c);tp++)            {                for(int j=0;j<c;j++)                //2层循环找最高点                {                    if(tp&(1<<j))continue;          //j点已经被用过                    if(e[i][b[j]]==0)continue;      //i,j之间没有边                    for(int k=j+1;k<c;k++)                    {                        if(tp&(1<<k))continue;      //k点被用过                        if(e[i][b[k]]==0)continue;  //i,k之间没有边                        d[now][tp|(1<<j)|(1<<k)]=max(d[now][tp|(1<<j)|(1<<k)],d[pre][tp]+1);                    }                }                ans=max(ans,d[now][tp]); //更新答案            }            pre^=1;            now^=1;        }        printf("%d\n",ans);    }    return 0;}


原创粉丝点击