POJ 3687-Labeling Balls(反向拓撲排序)
Labeling Balls
Time Limit: 1000MS | Memory Limit: 65536K |
Total Submissions: 16050 | Accepted: 4717 |
Description
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:
- No two balls share the same label.
- The labeling satisfies several constrains like "The ball labeled with a
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
Output
For each test case output on a single line the balls' weights from label 1 to label N. 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
Source
題目大意:給你n個球編號為1~n,和m個條件x y滿足編號為x的球比編號為y的球輕,讓你給每個編號的球賦一個重量,滿足前面的條件,若有多種答案輸出1~n編號球的重量的字典序最小的。沒有答案輸出“-1”。
解題思路:很容易想到拓撲排序,方法沒錯,但是這道題需要建反向圖再進行拓撲排序,這樣的結果才會是最優的,有的貪心的策略,例如有兩個條件:4 1 和 2 3
大家想到正向的策略肯定是,編號小的先出隊,重量從小的開始賦,反向的策略就是與正向相反。
如果採用正向拓撲排序的策略的話,那麼出隊的順序是 2 3 4 1,那麼球的重量為w[2] = 1,w[3] = 2,w[4] = 3,w[1] = 4,這樣的結果為4 1 2 3
然而採用反向拓撲排序的策略的話,那麼出隊的順序為 3 2 1 4,那麼球的重量為w[3] = 4,w[2] = 3,w[1] = 2,w[4] = 1,這樣的結果為2 3 4 1
顯然反向策略字典序最小,為什麼呢,因為要按編號字典序最小,如果我們正向拓撲排序的話,會把小的重量用掉了,這樣就會導致,可能你把小重量用到了編號大的球上,後面編號小的卻用了一個大的重量,所以不一定使得字典序最小,就如同上面那個例子,但是反著來就不一樣了,因為我們每次出隊編號大的,並且給他賦值重量大的,這樣的結果會使得字典序最小。
還有一個坑點:有重邊!!!
AC程式碼:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<math.h>
#include<cstdlib>
#include<stdlib.h>
#include<queue>
#include<map>
#include<set>
#include<stack>
#define bug printf("*********\n");
#define mem0(a) memset(a, 0, sizeof(a));
#define mem1(a) memset(a, -1, sizeof(a));
#define finf(a, n) fill(a, a+n, INF);
#define in1(a) scanf("%d" ,&a);
#define in2(a, b) scanf("%d%d", &a, &b);
#define in3(a, b, c) scanf("%d%d%d", &a, &b, &c);
#define out1(a) printf("%d\n", a);
#define out2(a, b) printf("%d %d\n", a, b);
#define pb(G, b) G.push_back(b);
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long LL;
typedef pair<LL, pair<int, LL> > LLppar;
typedef pair<int, int> par;
typedef pair<LL, int> LLpar;
const LL mod = 1e9+7;
const int INF = 1e9+7;
const int N = 1010;
const double pi = 3.1415926;
using namespace std;
int n, m, cnt;
int head[210];
int in[210], out[210], a[210];
int vis[210][210];
struct edge
{
int to;
int next;
}e[40010];
void add(int u, int v)
{
e[cnt].to = v;
e[cnt].next = head[u];
head[u] = cnt ++;
}
int ans[210];
bool topo()
{
priority_queue<int> q;
int sum = 0, k = n;
for(int i = 1; i <= n; i ++) {
if(in[i] == 0) {
q.push(i);
}
}
while(!q.empty()) {
int u = q.top();
q.pop();
sum ++;
ans[u] = k --;
for(int i = head[u]; ~i; i = e[i].next) {
int en = e[i].to;
in[en] --;
if(in[en] == 0) {
q.push(en);
}
}
}
if(sum != n) printf("-1\n");
else {
for(int i = 1; i <= n-1; i ++) {
printf("%d ", ans[i]);
}
printf("%d\n", ans[n]);
}
}
void inti()
{
mem1(head);
mem0(in);
mem0(out);
mem0(vis);
cnt = 0;
}
int main(int argc, char * argv[])
{
int x, y, z, T;
scanf("%d", &T);
while(T --) {
scanf("%d%d", &n, &m);
inti();
for(int i = 0; i < m; i ++) {
scanf("%d%d", &x, &y);
if(!vis[x][y]) { //有重邊
vis[x][y] = 1;
add(y, x);
in[x] ++;
out[y] ++;
}
}
topo();
}
}