POJ 3687 Labeling Balls (拓扑排序)
题意:给定m个球的关系,求出具有最小字典序的各个球的重量。
思路:拓扑排序,但是不能建正向图,只能建反向图,具体解释见Answeror牛:
http://www.answeror.com/archives/23913
PS:图论中的技巧太多,只靠做题感觉是亡羊补牢,只有把理论知识搞透彻,才能真正明白各个题中隐藏的数学原理,向这样正向和反向图中的细微区别也就yin不了人了...
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <memory.h>
#include <cmath>
#include <bitset>
#include <queue>
#include <vector>
using namespace std;
const int BORDER = (1<<20)-1;
const int MAXSIZE = 37;
const int MAXN = 205;
const int INF = 1000000000;
#define CLR(x,y) memset(x,y,sizeof(x))
#define ADD(x) x=((x+1)&BORDER)
#define IN(x) scanf("%d",&x)
#define OUT(x) printf("%d\n",x)
#define MIN(m,v) (m)<(v)?(m):(v)
#define MAX(m,v) (m)>(v)?(m):(v)
#define ABS(x) ((x)>0?(x):-(x))
typedef struct{
int v;
int next;
}Edge;
int index,n,m;
Edge edge[MAXN*MAXN];
int weight[MAXN],grad[MAXN],net[MAXN];
bool g[MAXN][MAXN],visit[MAXN];
void add_edge(const int& u,const int& v)
{
edge[index].v = v;
edge[index].next = net[u];
net[u] = index++;
}
int init()
{
index = 0;
CLR(visit,0);
CLR(net,-1);
CLR(grad,0);
CLR(g,0);
return 0;
}
int input()
{
int i,j,a,b;
scanf("%d%d",&n,&m);
for(i = 0; i < m; ++i)
{
scanf("%d %d",&a,&b);
if(!g[b][a])//判重
{
g[b][a] = true;
add_edge(b,a);//反向图
++grad[a];
}
}
return 0;
}
int work()
{
int i,j,tmp,mmin;
for(i = 0; i < n; ++i)//拓扑
{
for(j = n; j > 0 && grad[j]!=0; --j)
;
if(j <= 0)
{
printf("-1\n");
return 0;
}
grad[j] = -1;
weight[j] = n-i;
for(j = net[j]; j != -1; j = edge[j].next)
--grad[edge[j].v];
}
printf("%d",weight[1]);
for(i = 2; i <= n; ++i)
printf(" %d",weight[i]);
printf("\n");
return 0;
}
int main()
{
int t ;
IN(t);
while(t--)
{
init();
input();
work();
}
return 0;
}