http://codeforces.com/problemset/problem/274/D
这道题解题思路:
对每一行统计,以小值列作为弧尾,大值列作为弧头,(-1除外,不连弧),对得到的图做拓扑排序即可.
但本题数据较大,所以需要进行缩点,把相同数值的点缩在一起,成为一个新的大点,原先的小值列向大点连接,再由大点向大值列连接,可以减少边数
举例来说,原本取值为1的有4个点,取值为2的有5个点,
不缩点,就需要20条边
缩点,只需要4+1+5=10条边
(不过我还是觉得这个方法有点投机取巧??)
#include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int maxn=2e5+3;
typedef pair<int,int> P;
P a[maxn];
int deg[maxn];
bool used[maxn];
int ans[maxn];
vector <int >e[maxn];
queue<int> que;
int n,m,last,flast; int main(){
scanf("%d%d",&n,&m);
flast=m+1;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
scanf("%d",&a[j].first);
a[j].second=j+1;
}
sort(a,a+m); last=flast;
for(int j=0;j<m;){
if(a[j].first==-1){j++;continue;}
int k=j;
while(a[k].first==a[j].first){
e[a[k].second].push_back(last);
deg[last]++;
if(last>flast){
e[last-1].push_back(a[k].second);
deg[a[k].second]++;
}
k++;
}
last++;
j=k;
}
flast=last;
}
for(int i=1;i<=m;i++){
if(deg[i]==0){
que.push(i);
}
}
int len=0;
while(!que.empty()&&len<m){
int s=que.front();que.pop();
if(used[s])continue;
used[s]=true;
if(s<=m)ans[len++]=s;
for(int i=0;i<e[s].size();i++){
int t=e[s][i];
if(!used[t]){
deg[t]--;
if(deg[t]==0){
que.push(t);
}
}
}
}
if(len<m){
puts("-1");
}
else for(int i=0;i<len;i++){
printf("%d%c",ans[i],i==len-1?'\n':' ');
}
return 0;
}