问题:
xxxxxyt学姐经常一个人在家,难免会感到寂寞,于是学姐养了n只可爱的宠物,比如皮皮虾、大蟒蛇、藏狐、安康鱼…但即便如此学姐还是感到无聊。突然有一天,学姐想到了让宠物们互相对战的消遣方法(请不要给动物保护协会打电话!)。学姐让宠物们两两进行对战,n*(n-1)/2场对战后,学姐得到了一张相生相克图,然后又根据自己的喜好,把宠物们分成了一队与二队。就在队伍分好后,学姐的强迫症又犯了,她希望自己的两支队伍都满足这样一个性质:存在某种排列,使得排在后面的宠物能够击败排在前面的所有宠物。但学姐的懒惰大家都是知道的,所以她找到了你,希望你能告诉她这两支队伍是否均满足要求,如果是,她还希望你告诉她最多可以从二队中抽出多少只宠物放在一队,使得两支队伍仍然满足要求。努力解决问题吧,而xxxxxyt学姐,瘫躺。
输入格式
第一行输入两个数字n和m,分别表示学姐有n只宠物,其中被分到一队的宠物有m只。
接下来n行每行n个数字,ai,j表示第i只宠物是否能战胜第j只宠物,保证ai,i=0且ai,j==!aj,i。
接下来一行m个数字,表示有哪些宠物被分到了一队。
输出格式
如果两支队伍均不能让xxxxxyt满意,则输出“NO”;否则输出“YES”,并输出一个最大的k,使得从二队中非任意地抽出k只宠物放入一队后,两支队伍仍然满足条件。详细格式见样例输出。
解:
此题不能用tarjan贪心 可能出现环套环的情况
注意到这是一个有向完全图 所以top序列在不存在环的情况下一定是唯一的
并且题目还让你判断了环 这不明摆着让你利用top排序进行DP吗? 这种在top序列上进行Dp的方式其实很常见
考虑建立多层图
我们对唯一存在的topp 求两个topp序列 问题可以转化为
给你两个数列 AB 问题B最多能够插入A中多少并且B序列的顺序是不变的
预处理出B数列中的每一个数所能插入的位置
定义 f[i][j] 表示前i个A前i个B 所能选的最大的个数
状态转移方程就很好写具体看代码
code:
#include<stdio.h>
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
#define maxnn 2000
#define mm 1000010
int mapp[maxnn][maxnn];
int las[mm],en[mm],nex[mm],tot;
int rr1[mm],rr2[mm];
void add(int a,int b)
{
en[++tot]=b;
nex[tot]=las[a];
las[a]=tot;
}
int las1[mm],en1[mm],nex1[mm],tot1;
void add1(int a,int b)
{
en1[++tot1]=b;
nex1[tot1]=las1[a];
las1[a]=tot1;
}
int n,m;
int ru[maxnn];
int is[maxnn];
int rk1[maxnn],rk2[maxnn],cnt1,cnt2;
int maxx[maxnn],minn[maxnn];
void toppsort()
{
queue<int> Q;
int num=0;
for(int i=1;i<=n;i++)
{
if(is[i]&&(!ru[i]))
{
rk1[++cnt1]=i;
rr1[i]=cnt1;
Q.push(i);
num++;
}
}
while(Q.size())
{
int r=Q.front();Q.pop();
for(int i=las[r];i;i=nex[i])
{
int u=en[i];
if(!is[u]) continue;
ru[u]--;
if((!ru[u])&&(is[u]))
{
num++;
rk1[++cnt1]=u;rr1[u]=cnt1;
Q.push(u);
}
}
}
if(num<m) {puts("NO"); exit(0);}
num=0;
for(int i=1;i<=n;i++)
{
if((!is[i])&&(!ru[i]))
{
Q.push(i);
rk2[++cnt2]=i;
rr2[i]=cnt2;
num++;
}
}
while(Q.size())
{
int r=Q.front(); Q.pop();
for(int i=las[r];i;i=nex[i])
{
int u=en[i];
if(is[u]) continue;
ru[u]--;
if((!ru[u])&&(!is[u]))
{
rk2[++cnt2]=u;
rr2[u]=cnt2;
Q.push(u);
num++;
}
}
}
if(num<n-m)
{
puts("NO"); exit(0);
}
}
int f[maxnn][maxnn];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&mapp[i][j]);
if(mapp[i][j]==1)
{
add(j,i);
add1(i,j);
}
}
}
int x;
for(int i=1;i<=m;i++)
{
scanf("%d",&x);
is[x]=1;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(mapp[i][j]&&is[i]&&is[j])ru[i]++;
if(mapp[i][j]&&(!is[i])&&(!is[j])) ru[i]++;
}
toppsort();
for(int i=1;i<=n;i++)
{
minn[i]=100000;
}
for(int i=1;i<=n;i++)
{
if(is[i])
for(int j=las1[i];j;j=nex1[j])
{
int u=en1[j];
if(!is[u])
{
if(minn[u]==0) minn[rr2[u]]=rr1[i];
else minn[rr2[u]]=min(minn[rr2[u]],rr1[i]);
}
}
else
{
for(int j=las1[i];j;j=nex1[j])
{
int u=en1[j];
if(is[u])
maxx[rr2[i]]=max(maxx[rr2[i]],rr1[u]);
}
}
}
int ans=0;
for(int i=0;i<=cnt1+1;i++)
for(int j=0;j<=cnt2;j++)
{
if(i>=1) f[i][j]=max(f[i-1][j],f[i][j]);
if(j>=1) f[i][j]=max(f[i][j-1],f[i][j]);
if((i>maxx[j])&&(i<=minn[j]))
{
if(j>=1)f[i][j]=max(f[i][j],f[i][j-1]+1);
}
ans=max(ans,f[i][j]);
}
printf("YES ");
cout<<ans;
}