Codeforces Round #541 (Div. 2) D. Gourmet choice(level 1)(拓扑排序)

题目链接

题意:

有两个数组a[],b[],分别由n个和m个

然后给你一个n*m的矩阵

mp[i,j]='>'  表示a[i]>b[j]

mp[i,j]='=' 表示a[i]=b[j]

mp[i,j]='<' 表示a[i]<b[j]

让你输出满足条件的答案,并且这组答案要是所有元素最大值最小的那组

 

解析:

这道题....又脑子挂了..一直在比较同一组元素的大小..虽然最后做出来了...但花了两个小时....

我的思路就是先把b[]排出来,根据‘>’ b[j]--,'=' b[j]+=0 ,'<' b[j]++

把b[]都增大1000倍,好计算下面的a[]

然后再根据排出来的b[],来算a[],注意这里因为会有No的情况,

所以在这个过程中,你可能找不到满足条件的a[i],那么这个时候直接输出No就可以了...

之前就一直在纠结怎么判断No....只要先算出来解,在回去判断就可以了..

那么最后把a,b合并,离散化输出

#include <bits/stdc++.h>
using namespace std;

const int N = 1e3+10;
const int INF = 0x3f3f3f3f;

char mp[N][N];

int sec[N],fir[N];
int num[3];


int b[N+N];

int main()
{
   int n,m;
   scanf("%d%d",&n,&m);
   for(int i=1;i<=n;i++)
   {
       getchar();
       scanf("%s",mp[i]+1);
   }

   for(int i=1;i<=n;i++)
   {
       for(int j=1;j<=m;j++)
       {
           if(mp[i][j]=='>') sec[j]--;
           else if(mp[i][j]=='<') sec[j]++;
       }
   }
   int flag=1;
   for(int j=1;j<=m;j++)
        sec[j]*=1000;

   for(int i=1;i<=n;i++)
   {
       num[0]=num[1]=INF;  //'=','<','>'
       num[2]=-INF;
       for(int j=1;j<=m;j++)
       {
           if(mp[i][j]=='=')
           {
               if(num[0]==INF) num[0]=sec[j];
               else if(num[0]!=sec[j]) flag=0;
           }
           else if(mp[i][j]=='<')
           {
               num[1]=min(sec[j],num[1]);
           }
           else
           {
               num[2]=max(sec[j],num[2]);
           }

       }
       if(!flag) break;
       if(num[2]>=num[1]) flag=0;
       else if(num[0]!=INF)
       {
           if(num[0]<num[1]&&num[0]>num[2])
                fir[i]=num[0];
           else
                flag=0;
       }
       else
            fir[i]=num[2]+1;
       if(!flag) break;
   }

   if(flag){
       for(int i=1;i<=n;i++)
       {
           for(int j=1;j<=m;j++)
           {
               if(fir[i]>sec[j])
               {
                   if(mp[i][j]!='>') {flag=0;break;}
               }
               else if(fir[i]==sec[j])
               {
                   if(mp[i][j]!='=') {flag=0;break;}
               }
               else
               {
                   if(mp[i][j]!='<') {flag=0;break;}
               }
           }
           if(!flag) break;
       }


       int tot=0;
       for(int i=1;i<=n;i++) b[++tot]=fir[i];
       for(int j=1;j<=m;j++) b[++tot]=sec[j];
       sort(b+1,b+1+tot);
       int cnt=unique(b + 1, b + tot + 1) - b - 1;
       for(int i=1;i<=n;i++)
            fir[i]=lower_bound(b+1,b+1+cnt,fir[i])-b;
       for(int j=1;j<=m;j++)
            sec[j]=lower_bound(b+1,b+1+cnt,sec[j])-b;
   }

   if(!flag) printf("No\n");
   else
   {
       printf("Yes\n");
       for(int i=1;i<=n;i++)
            if(i==1) printf("%d",fir[i]);
            else printf(" %d",fir[i]);
       printf("\n");
       for(int j=1;j<=m;j++)
            if(j==1) printf("%d",sec[j]);
            else printf(" %d",sec[j]);
        printf("\n");

   }
}

不过上面的做法太烦了...这道题其实就是一道拓扑排序的裸题....

mp都给你了,只要把里面的相等的一对数,归到一个并查集,然后根据'<' '>'建边

然后拓扑排序一遍就可以了

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;

const int N = 2e3+10;
typedef pair<int,int> PII;
char mp[N][N];
int fa[N];
int num[N];
int deg[N],tot;

vector<int> Less_than[N];  //More_than


int findfa(int x)
{
	if(x==fa[x]) return fa[x];
	int nex=fa[x];
	fa[x]=findfa(nex);
	return fa[x];
}

inline void unite(int x,int y)
{
	int fx,fy;
	fx=findfa(x);
	fy=findfa(y);
	if(fx!=fy) fa[fx]=fy;
}

queue<PII> mq;

void toposort()
{
	for(int i=1;i<=tot;i++)
		if(!deg[i]&&findfa(i)==i) mq.push(make_pair(i,1)),num[i]=1;
	while(!mq.empty())
	{
		PII u=mq.front();
		mq.pop();
		for(auto x:Less_than[u.first])
		{
			deg[x]--;
			if(!deg[x]) 
			{
				num[x]=u.second+1;
				mq.push(make_pair(x,num[x]));
			}
		}
	}
}

int main()
{
	int n,m;
	
	scanf("%d%d",&n,&m);
	tot=n+m;
	for(int i=1;i<=n;i++)
		scanf("%s",mp[i]+1);
	for(int i=1;i<=tot;i++)
		fa[i]=i;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
			if(mp[i][j]=='=') unite(i,n+j);
	}

	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
			if(mp[i][j]=='<')
				Less_than[findfa(i)].push_back(findfa(n+j)),deg[findfa(n+j)]++;
			else if(mp[i][j]=='>')
				Less_than[findfa(n+j)].push_back(findfa(i)),deg[findfa(i)]++;
	}
	

	memset(num,-1,sizeof(num));
	toposort();
	int flag=1;
	for(int i=1;i<=tot;i++)
	{
		if(i==findfa(i)&&num[i]==-1)
				{flag=0;break;}
	}
	if(!flag) printf("No\n");
	else
	{
		printf("Yes\n");
		for(int i=1;i<=n;i++)
		{
			if(i>1) printf(" ");
			printf("%d",num[findfa(i)]);
		}
		printf("\n");
		for(int i=1;i<=m;i++)
		{
			if(i>1) printf(" ");
			printf("%d",num[findfa(n+i)]);
		}
		printf("\n");
	}
	
	
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值