POJ 3687 Labeling Balls(反向拓扑+贪心思想!!!非常棒的一道题)
Posted 若有恒,何必三更起五更眠;最无益,莫过一日曝十日寒。
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 3687 Labeling Balls(反向拓扑+贪心思想!!!非常棒的一道题)相关的知识,希望对你有一定的参考价值。
Labeling Balls
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:
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 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 POJ Founder Monthly Contest – 2008.08.31, windy7926778
|
题目意思:
给你n个球和m组关系,关系a b表示a比b轻,在符合这些要求的条件下,给他们贴标签
要求轻的球标签也要小,最后要你输出这些球的重量顺序
第一次的做法:
一开始的思路是用一个优先队列,从而做到从小到大取标签,
保证标签号小的在序列的尽可能前面,这样对于比较小的标签,
就可以得到比较小的重量了。
然后妥妥的wa
因为我输出的整个标签的序列而不是每个标签所对应的球的重量。
改完以后交了,还是错,想了好久,
看了别人的思路都说这道题要反向建图,
在从大往小的取,将大的数尽量放到答案的后面,
这样就能够保证小重量的球尽可能的放到了前面。
题目意思一开始就看错了两个地方
1.要求输出的不是标签顺序,而是重量的顺序
2.没有理解轻的球其标签也要小
正解:
分析;
给了你m组关系,a b表示标签为a比标签为b轻
我们可以先得到标签的顺序,然后再变化一下得到每个标签对应的重量
求标签的顺序:
要使得轻的球其标签小,也就是轻的放标签序列的前面
如果按照我一开始的做法,正向拓扑,然后每次选标签小的放前面
这样是不行的,因为即使该点最小,但是它后面连接的点未必是最小的啊
比如:
6->4->1
\
3->9->2 ->0
/
5->7->8
1,2,8都是指向0的,不好画
如果取入度为0且最小的话,那么是先取3,而我们的目的是让标号小的尽量靠前,即让1靠前,这与先取3是相违背的
所以我一开始的做法的确不行
因为题目是要满足轻的球标签小,所以正确做法:
每次让标签号大的尽量完后排,因为从后往前看,位置是越来越重要的!
贪心的思想
所以我们反向建边就是b比a重,每次选择标签号大的从最后面开始
因为越到前面,是越来越重要的,我们先从不重要的开始放,最后再放最重要的(同时最后放的也是在满足约束的条件下,标签号最小的)
样例:
5 3
1 4
4 2
3 5
反向建图:
2->4->1
5->3
每次选择标签号大的排(从后往前排)
那么拓扑得到的标签顺序就是:1 4 2 3 5
再求其重量排序:(重量为2的排在第3个,重量为3的排在第四个)
1 3 4 2 5
#include<stdio.h> #include<iostream> #include<math.h> #include<string.h> #include<set> #include<map> #include<list> #include<queue> #include<algorithm> using namespace std; typedef long long LL; int mon1[13]= {0,31,28,31,30,31,30,31,31,30,31,30,31}; int mon2[13]= {0,31,29,31,30,31,30,31,31,30,31,30,31}; int dir[4][2]= {{0,1},{0,-1},{1,0},{-1,0}}; int getval() { int ret(0); char c; while((c=getchar())==‘ ‘||c==‘\n‘||c==‘\r‘); ret=c-‘0‘; while((c=getchar())!=‘ ‘&&c!=‘\n‘&&c!=‘\r‘) ret=ret*10+c-‘0‘; return ret; } #define max_v 205 int indgree[max_v]; vector<int> vv[max_v]; priority_queue<int,vector<int>,less<int> > q; int n,m; int a[max_v]; int tpsort() { for(int i=1;i<=n;i++) { if(indgree[i]==0) q.push(i); } int temp; int cnt=0; int k=n; while(!q.empty()) { temp=q.top(); q.pop(); a[temp]=k--; cnt++; for(int i=0;i<vv[temp].size();i++) { indgree[vv[temp][i]]--; if(indgree[vv[temp][i]]==0) q.push(vv[temp][i]); } } if(cnt!=n) return 1; else return 0; } int main() { int t; int x,y; scanf("%d",&t); while(t--) { scanf("%d %d",&n,&m); if(m==0) { for(int i=1;i<=n;i++) { if(i==1) printf("%d",i); else printf(" %d",i); } printf("\n"); continue; } memset(indgree,0,sizeof(indgree)); for(int i=1;i<=n;i++) vv[i].clear(); while(!q.empty()) q.pop(); int flag1=0;//环 for(int i=1;i<=m;i++) { scanf("%d %d",&y,&x); if(flag1==0) { if(x==y) { flag1=1; continue; } if(count(vv[x].begin(),vv[x].end(),y)==0) { vv[x].push_back(y); indgree[y]++; } } } if(flag1==0) flag1=tpsort(); if(flag1) { printf("-1\n"); continue; } for(int i=1;i<=n;i++) { if(i==1) printf("%d",a[i]); else printf(" %d",a[i]); } printf("\n"); } return 0; } /* 题目意思: 给你n个球和m组关系,关系a b表示a比b轻,在符合这些要求的条件下,给他们贴标签 要求轻的球标签也要小,最后要你输出这些球的重量顺序 第一次的做法: 一开始的思路是用一个优先队列,从而做到从小到大取标签, 保证标签号小的在序列的尽可能前面,这样对于比较小的标签, 就可以得到比较小的重量了。 然后妥妥的wa 因为我输出的整个标签的序列而不是每个标签所对应的球的重量。 改完以后交了,还是错,想了好久, 看了别人的思路都说这道题要反向建图, 在从大往小的取,将大的数尽量放到答案的后面, 这样就能够保证小重量的球尽可能的放到了前面。 题目意思一开始就看错了两个地方 1.要求输出的不是标签顺序,而是重量的顺序 2.没有理解轻的球其标签也要小 正解: 分析; 给了你m组关系,a b表示标签为a比标签为b轻 我们可以先得到标签的顺序,然后再变化一下得到每个标签对应的重量 求标签的顺序: 要使得轻的球其标签小,也就是轻的放标签序列的前面 如果按照我一开始的做法,正向拓扑,然后每次选标签小的放前面 这样是不行的,因为即使该点最小,但是它后面连接的点未必是最小的啊 比如: 6->4->1 3->9->2 -0 / 5->7->8 1,2,8都是指向0的,不好画 如果取入度为0且最小的话,那么是先取3,而我们的目的是让标号小的尽量靠前,即让1靠前,这与先取3是相违背的 所以我一开始的做法的确不行 因为题目是要满足轻的球标签小,所以正确做法: 每次让标签号大的尽量完后排,因为从后往前看,位置是越来越重要的! 贪心的思想 所以我们反向建边就是b比a重,每次选择标签号大的从最后面开始 因为越到前面,是越来越重要的,我们先从不重要的开始放,最后再放最重要的(同时最后放的也是在满足约束的条件下,标签号最小的) 样例: 5 3 1 4 4 2 3 5 反向建图: 2->4->1 5->3 每次选择标签号大的排(从后往前排) 那么拓扑得到的标签顺序就是:1 4 2 3 5 再求其重量排序:(重量为2的排在第3个,重量为3的排在第四个) 1 3 4 2 5 */
以上是关于POJ 3687 Labeling Balls(反向拓扑+贪心思想!!!非常棒的一道题)的主要内容,如果未能解决你的问题,请参考以下文章
POJ 3687 Labeling Balls(特殊的拓扑排序)
POJ 3687 Labeling Balls(反向拓扑+贪心思想!!!非常棒的一道题)