2016多校训练Contest7: 1003 Colosseo hdu5811

Problem Description
Mr. Chopsticks keeps N monsters, numbered from 1 to N. In order to train them, he holds N * (N - 1) / 2 competitions and asks the monsters to fight with each other. Any two monsters fight in exactly one competition, in which one of them beat the other. If monster A beats monster B, we say A is stronger than B. Note that the “stronger than” relation is not transitive. For example, it is possible that A beats B, B beats C but C beats A.

After finishing all the competitions, Mr. Chopsticks divides all the monsters into two teams T1 and T2, containing M and N – M monsters respectively, where each monster is in exactly one team. Mr. Chopsticks considers a team of monsters powerful if there is a way to arrange them in a queue (A1, A2, …, Am) such that monster Ai is stronger than monster Aj for any 1<=i<j<=m. Now Mr. Chopsticks wants to check whether T1 and T2 are both powerful, and if so, he wants to select k monsters from T2 to join T1 such that the selected monsters together with all the monsters in T1 can still form a powerful team and k is as large as possible. Could you help him?
 

Input
The input contains multiple test cases. Each case begins with two integers N and M (2 <= N <= 1000, 1 <= M < N), indicating the number of monsters Mr. Chopsticks keeps and the number of monsters in T1 respectively. The following N lines, each contain N integers, where the jth integer in the ith line is 1 if the ith monster beats the jth monster; otherwise, it is 0. It is guaranteed that the ith integer in the jth line is 0 iff the jth integer in the ith line is 1. The ith integer in the ith line is always 0. The last line of each case contains M distinct integers, each between 1 and N inclusively, representing the monsters in T1. The input is terminated by N = M = 0.
 

Output
For each case, if both T1 and T2 are powerful, output “YES” and the maximum k; otherwise, output “NO”.
 

Sample Input
  
  
3 2 0 1 1 0 0 1 0 0 0 3 1 4 3 0 1 0 1 0 0 1 1 1 0 0 1 0 0 0 0 1 2 3 4 2 0 1 0 1 0 0 1 1 1 0 0 1 0 0 0 0 1 2 0 0
 

Sample Output
  
  
YES 1 NO YES 1
Hint
In the third example, Mr. Chopsticks can let the monster numbered 4 from T2 join into T1 to form a queue (1, 2, 4).

首先我们暴力判断T1和T2是否都满足

判断方法是对于每个点i,判断能到达多少个点

然后看这些数量是否为1到m或n-m的排列

然后考虑问题2

因为T2满足。所以我们按照T2顺序插入可以不用考虑T2之间互相影响

对于每个T2,找到可以插入的T1的位置,不能插入则直接删除这个点

因为T2满足题意,所以T2是个DAG,因此我们拓扑排序,每个点有个权值表示可以插入的T1的位置

找权值单调不下降的最长链的长度即为答案

这题一开始T了我以为是常数写大了。。结果是scanf的耗时太多了。加了个读入优化就卡过去了

#include<map>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
inline long long read()
{
    long long x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int mx[1001][1001];
bool v[1001];
int vx[1001];
int a[1001],b[1001],c[1001],f[1001];
struct line
{
	int s,t;
	int next;
}aa[1000001];
int head[1001];
int edge;
inline void add(int s,int t)
{
	aa[edge].next=head[s];
	head[s]=edge;
	aa[edge].s=s;
	aa[edge].t=t;
}
int deg[1001];
queue<int> Q;
int main()
{
//	freopen("1003.in","r",stdin);
//	freopen("1003.ans","w",stdout);
	int n,m;
	n=read();
	m=read();
//	scanf("%d%d",&n,&m);
	while(n!=0&&m!=0)
	{
		int i,j,k;
		for(i=1;i<=n;i++)
			for(j=1;j<=n;j++)
				mx[i][j]=read();
			//	scanf("%d",&mx[i][j]);
		memset(v,false,sizeof(v));
		for(i=1;i<=m;i++)
		{
			a[i]=read();
		//	scanf("%d",&a[i]);
			v[a[i]]=true;
		}
		int p=0;
		for(j=1;j<=n;j++)
		{
			if(!v[j])
			{
				p++;
				b[p]=j;
			}
		}
		bool flag=true;
		memset(vx,0,sizeof(vx));
		for(i=1;i<=n-m;i++)
		{
			int sx=0;
			for(j=1;j<=n-m;j++)
			{
				if(mx[b[i]][b[j]])
					sx++;
			}
			if(!vx[sx])
				vx[sx]=1;
			else
			{
				flag=false;
				break;
			}
		}
		memset(vx,0,sizeof(vx));
		for(i=1;i<=m;i++)
		{
			int sx=0;
			for(j=1;j<=m;j++)
			{
				if(mx[a[i]][a[j]])
					sx++;
			}
			if(!vx[sx])
				vx[sx]=a[i];
			else
			{
				flag=false;
				break;
			}
		}
		if(flag)
		{
			printf("YES ");
			for(i=1;i<=n-m;i++)
			{
				int sx=0,la=0;
				bool flag=true;
				for(j=0;j<m;j++)
				{
					if(mx[b[i]][vx[j]])
					{
						sx++;
						la=j+1;
					}
					else
						break;
				}
				for(k=j;k<m;k++)
				{
					if(!mx[vx[k]][b[i]])
					{
						flag=false;
						break;
					}
				}
				if(flag)
					c[i]=n-la;
				else
					c[i]=2100000000;
			}
		//	sort(c+1,c+1+n-m);
			memset(f,0,sizeof(f));
			memset(head,0,sizeof(head));
			//memset(aa,0,sizeof(aa));
			memset(deg,0,sizeof(deg));
			edge=0;
			int ans=0;
			for(i=1;i<=n-m;i++)
			{
				if(c[i]==2100000000)
					continue;
				for(j=1;j<=n-m;j++)
				{
					if(c[j]!=2100000000)
					{
						if(mx[b[i]][b[j]])
						{
							edge++;
							add(i,j);
							deg[j]++;
						}
					}
				}
			}
			memset(f,0,sizeof(f));
			for(i=1;i<=n-m;i++)
			{
				if(c[i]==2100000000)
					continue;
				if(deg[i]==0)
					Q.push(i);
			}
			while(!Q.empty())
			{
				int d=Q.front();
				f[d]=max(f[d],1);
				Q.pop();
				for(i=head[d];i!=0;i=aa[i].next)
				{
					int t=aa[i].t;
					deg[t]--;
					if(c[d]<=c[t])
						f[t]=max(f[t],f[d]+1);
					if(deg[t]==0)
						Q.push(t);
				}
				ans=max(ans,f[d]);
			}
			printf("%d\n",ans);
		}
		else
			printf("NO\n");
		n=read();
		m=read();;
	//	scanf("%d%d",&n,&m);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值