poj 3687 反向建图 拓扑排序

来源:互联网 发布:mac用什么散热 编辑:程序博客网 时间:2024/06/05 14:36

题目链接http://poj.org/problem?id=3687

题目大意:

拓扑排序

给出一系列的关系,也就是a b两个数,必须保证 贴a标签的球在贴b标签的球的前面,最后排出一个序列,但是要注意的是最后的输出不是这个序列,而是从标签1到标签n所对应的球的重量,如果有多个解,那么就要让前面的标签所对应的重量尽可能的小。。


一开始的思路是用一个优先队列,从而做到从小到大取标签,保证标签号小的在序列的尽可能前面,这样对于比较小的标签,就可以得到比较小的重量了。

交了第一次,妥妥的WA了,因为我输出的整个标签的序列而不是每个标签所对应的球的重量。改完以后交了,还是错,想了好久,看了别人的思路都说这道题要反向建图,在从大往小的取,将大的数尽量放到答案的后面,这样就能够保证小重量的球尽可能的放到了前面。

看到一姐的博客说:每一次让序号大的数尽量往后排,因为从后往前排的时候,决定的位置是越来越重要的。

如果是正向构图的话很容易找出一个反例,

5 4

5 2 

2 1

4 3 

3 1

如果正向构图那么就是5->2->1   4->3->1   这样的话标签序列就会是(4 3 5 2 1) 所对应的答案就是(5 4 2 1 3) 

如果反向构图从大往小的取,并尽可能的将大的放到后面话(也就是将相互之间的方向颠倒一下)  5<-2<-1   4<-3<-1 标签序列就变成(5 2 4 3 1)  答案就是(5 2 4 3 1 )

反向的话才可以找到最优解,,如果正向的话每次取最小,前面的位置是比后面的位置来的重要的,所以并不能保证之前的就是足够小的了,可能有比他更小的情况存在。

反着来,将最大的放到越后面,这样剩下的就是比较小的,也就可以放到前面更加重要的位置中去了。

不过不知道怎么证明这种算法的正确性

这题感觉蛮好的,以后还要再来看看。

代码:

#include <iostream>#include <vector>#include <queue>#include <cstring>#include <cstdio>using namespace std;#define M 50000#define INF 1000000int n,m;int flag;vector<int> G[M];int indegree[M];int judge[300][300];int ans[M];void toposort(){    priority_queue<int> q;   //优先队列 从大的往小的取    int num = n;    for(int i = 1;i <= n;i++)    {        if(indegree[i]==0)            q.push(i);    }    while(!q.empty())    {        int cur = q.top();        q.pop();        ans[cur] = num;  // 将每个标签从后往前放        num--;        for(int i = 0;i <= n;i++)        {            if(judge[cur][i]==1)            {                indegree[i]--;                if(!indegree[i])                    q.push(i);            }        }    }    if(num>0) flag = 1; //判环}int main(){    int t;    cin >> t;    while(t--)    {        flag = 0;        cin >> n >> m;        memset(indegree,0,sizeof(indegree));        memset(judge,0,sizeof(judge));        for(int i = 0;i < m;i++)        {            int a,b;            cin >> a >> b;            if(a==b) flag =1;            if(judge[b][a]==1) continue;   // 判重即是否之前有一样的            judge[b][a] = 1;   //反向构图就是将两个元素的指向相反            if(flag) continue;            indegree[a]++;        }        toposort();        //getchar();        if(flag) cout << -1 << endl;        else        {            for(int i = 1;i < n;i++)                cout << ans[i] << " ";            cout << ans[n] << endl;        }    }    return 0;}


0 0