版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/monochrome00/article/details/83624889
题目链接<http://codeforces.com/gym/101503/problem/I>
题意:
有一个n*n的矩阵,里面的数字为1~n*n,给出每个位置在它上边和左边有多少个大于它的数。构造出这么一个矩阵。
题解:
可以得知每一行每一列的大小顺序,每一行每一列从小到大依次连边。
如果从小到大依次填入数字,这样就能够确定因果关系。
然后做一次拓扑排序判断有无结果并输出即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=6e2+7;
const int M=1e6+7;
int a[N][N],b[N][N],n;
int od[N];
struct Edge{
int u,v,nxt;
Edge(int u=0,int v=0,int nxt=0):u(u),v(v),nxt(nxt){}
}e[M];
int p[M],edn;
void add(int u,int v){
e[++edn]=Edge(u,v,p[u]);p[u]=edn;
}
int ans[N][N],d[N*N];
bool Tsort(){
queue<int>q;
for(int i=0;i<n*n;i++){
if(d[i]==0) q.push(i);
}
int cnt=0;
while(!q.empty()){
int u=q.front();q.pop();
ans[u/n][u%n]=++cnt;
for(int i=p[u];~i;i=e[i].nxt){
int v=e[i].v;
d[v]--;
if(d[v]==0) q.push(v);
}
}
if(cnt<n*n) return false;
return true;
}
int main()
{
memset(p,-1,sizeof(p));edn=-1;
scanf("%d",&n);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
scanf("%d",&a[i][j]);
bool flag=true;
for(int j=0;j<n;j++){
memset(od,-1,sizeof(od));
for(int i=n-1;i>=0;i--){
int tmp=a[i][j];
int id=i*n+j;
int k=n-1;
while(tmp&&k>=0){
if(od[k]==-1) tmp--;
k--;
}
while(od[k]!=-1&&k>=0) k--;
if(k<0){flag=false;break;}
else od[k]=id;
}
if(!flag) break;
for(int k=0;k<n-1;k++){
add(od[k],od[k+1]);
d[od[k+1]]++;
}
}
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
scanf("%d",&b[i][j]);
for(int i=0;i<n;i++){
memset(od,-1,sizeof(od));
for(int j=n-1;j>=0;j--){
int tmp=b[i][j];
int id=i*n+j;
int k=n-1;
while(tmp&&k>=0){
if(od[k]==-1) tmp--;
k--;
}
while(od[k]!=-1&&k>=0) k--;
if(k<0){flag=false;break;}
else od[k]=id;
}
if(!flag) break;
for(int k=0;k<n-1;k++){
add(od[k],od[k+1]);
d[od[k+1]]++;
}
}
if(!flag||!Tsort()){printf("0\n");return 0;}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++)
printf("%d ",ans[i][j]);
printf("\n");
}
}