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?' ':' '); } return 0; }