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;
}