poj 3687 Labeling Balls - 贪心 - 拓扑排序

时间:2022-08-04 18:21:02

Windy has N balls of distinct weights from 1 unit to N units. Now he tries to label them with 1 to N in such a way that:

  1. No two balls share the same label.
  2. The labeling satisfies several constrains like "The ball labeled with a is lighter than the one labeled with b".

Can you help windy to find a solution?

Input

The first line of input is the number of test case. The first line of each test case contains two integers, N (1 ≤ N ≤ 200) and M (0 ≤ M ≤ 40,000). The next M line each contain two integers a and b indicating the ball labeled with a must be lighter than the one labeled with b. (1 ≤ a, b ≤ N) There is a blank line before each test case.

Output

For each test case output on a single line the balls' weights from label 1 to labelN. If several solutions exist, you should output the one with the smallest weight for label 1, then with the smallest weight for label 2, then with the smallest weight for label 3 and so on... If no solution exists, output -1 instead.

Sample Input

5

4 0

4 1
1 1 4 2
1 2
2 1 4 1
2 1 4 1
3 2

Sample Output

1 2 3 4
-1
-1
2 1 3 4
1 3 2 4

  题目大意 找出原图的一个拓扑序,使得1尽量靠前,2尽量靠前....(注意输出的是第i个球的重量是第几小)。无解输出-1.

  我学长给出了一个正确性很显然的做法

  正向建图,把当前集合中的点中最小点找出来,然后再暴力统计有多少个点指向它,那么这些点一定在它之前,就可以将原DAG分成两部分递归处理。时间复杂度O(n(n + m))

Code

Click here to view

  还有个做法是反向建图,然后用大根堆去跑拓扑排序,最后输出的时候reverse一遍。虽然n变成了log2n,但是似乎正确性不是那么的显然。

  如果解释的话可以这么想,正向建图,跑小根堆先把小的取走,保证了在大的尽量在后面,但是无法保证小的尽量在前面,比如说下面这个建出来的DAG。

poj 3687 Labeling Balls - 贪心 - 拓扑排序   这真是一个优美的反例。

  而反向建图跑大根堆,可以保证大的先被取走,自然小的就留在后面,reverse后,小的就跑到前面去了。

  下面给出一个并不太严谨的证明(有问题一定要指出来)

  假定存在一个更优的答案,那么第一处不相同的地方一定满足这个算法跑出来的值比这个答案大,因为前面的都相同,又因为都是1 ~ n的一个排列,那么意味着一定存在某个位置,这个答案比这个算法跑出来的值大。这意味着答案取出了比拓扑序某个时候,入度为0的点的最大值还大的数,这显然是不可能的。所以不存在更有的答案,所以这个答案就是最优的答案。

Code

 /**
* poj
* Problem#3687
* Accepted
* Time:32ms
* Memory:1116k
*/
#include <iostream>
#include <cstdio>
#include <ctime>
#include <cmath>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <vector>
#include <stack>
#ifndef WIN32
#define Auto "%lld"
#else
#define Auto "%I64d"
#endif
using namespace std;
typedef bool boolean;
const signed int inf = (signed)((1u << ) - );
const double eps = 1e-;
const int binary_limit = ;
#define smin(a, b) a = min(a, b)
#define smax(a, b) a = max(a, b)
#define max3(a, b, c) max(a, max(b, c))
#define min3(a, b, c) min(a, min(b, c))
template<typename T>
inline boolean readInteger(T& u){
char x;
int aFlag = ;
while(!isdigit((x = getchar())) && x != '-' && x != -);
if(x == -) {
ungetc(x, stdin);
return false;
}
if(x == '-'){
x = getchar();
aFlag = -;
}
for(u = x - ''; isdigit((x = getchar())); u = (u << ) + (u << ) + x - '');
ungetc(x, stdin);
u *= aFlag;
return true;
} ///map template starts
typedef class Edge{
public:
int end;
int next;
Edge(const int end = , const int next = -):end(end), next(next){}
}Edge; typedef class MapManager{
public:
int ce;
int *h;
vector<Edge> edge;
MapManager(){}
MapManager(int points):ce(){
h = new int[(const int)(points + )];
memset(h, -, sizeof(int) * (points + ));
}
inline void addEdge(int from, int end){
edge.push_back(Edge(end, h[from]));
h[from] = ce++;
}
inline void addDoubleEdge(int from, int end){
addEdge(from, end);
addEdge(end, from);
}
Edge& operator [] (int pos) {
return edge[pos];
}
inline void clear() {
edge.clear();
delete[] h;
}
}MapManager;
#define m_begin(g, i) (g).h[(i)]
#define m_endpos -1
///map template ends int n, m;
MapManager g;
int* dag;
int* dep; inline boolean init() {
if(!readInteger(n)) return false;
readInteger(m);
g = MapManager(n);
dag = new int[(n + )];
dep = new int[(n + )];
memset(dag, , sizeof(int) * (n + ));
for(int i = , a, b; i <= m; i++) {
readInteger(a);
readInteger(b);
g.addEdge(b, a);
dag[a]++;
}
return true;
} priority_queue<int> que;
inline void topu() {
for(int i = ; i <= n; i++)
if(!dag[i]) {
que.push(i);
}
int cnt = ;
while(!que.empty()) {
int e = que.top();
dep[e] = cnt++;
que.pop();
for(int i = m_begin(g, e); i != m_endpos; i = g[i].next) {
int& eu = g[i].end;
dag[eu]--;
if(!dag[eu])
que.push(eu);
}
}
} inline void solve() {
topu();
for(int i = ; i <= n; i++) {
if(dag[i]) {
puts("-1");
return;
}
}
for(int i = ; i <= n; i++)
printf("%d ", n - dep[i]);
putchar('\n');
} inline void clear() {
g.clear();
delete[] dep;
delete[] dag;
} int T;
int main() {
readInteger(T);
while(T--) {
init();
solve();
clear();
}
return ;
}