POJ 3687 Labeling Balls

次元传送门

题意:
其实我也没看题,听说是有一堆小球什么的,总之就是有n个未知数,分别对应1~n这n个数字,我们姑且给他们取个名字叫X1,X2…Xn。题目将输入一堆不等式,如”1 2”表示X1 < X2。而题目要求你将1~n付给这n个未知数,使得他们满足给出的不等式组,且使X1尽可能小,其次X2尽可能小……最次Xn尽可能小。

分析:
拓扑排序解此题,值得注意的是,如果直接将输入X Y存为一条X -> Y的边,然后跑一便拓扑排序,按排序对X们依次从小到大赋值,这种想法虽然看着挺对,但并不完美。假如某一时刻有X3和X4两个点都是0入度,你想选哪个呢?你会说,选X3,因为他的优先级高。嗯嗯很有道理,但这只是局部的贪心策略,并不能保证最后X1就一定比先选X4小。所以,这种算法也是错误的。
于是乎,肿么办?
答案是——把图倒过来存,还是拓扑排序,但是倒过来跑,先出去的点赋当前的最大值。
为啥子嘞?
反图下,如果一个边入度为0,说明他不需要比当前图里的任何边小,嘿嘿,好啊,既然你这么不挑不拣,那就赋给你当前的最大值吧(GOOD JOB,小子)。而且当多个点入度为零,选最大的那个,反正这是赋最大值,保证以后的优先级更高的未知数的解不会次于最优解,说白了就是最优解了。
慢慢品味吧,骚年,老朽直接放代码了。

代码实现

#include<iostream>
#include<cstring>
#include<cstdio>
#include<bitset>
using namespace std;
const int maxn=201;
bitset<maxn> b[maxn];
int c,n,m,i,j,x,y,ans[maxn];
int main(){
  cin>>c;
  while(c--){
    for(i=0;i<maxn;i++)
      b[i].reset();
    memset(ans,0,sizeof(ans));
    cin>>n>>m;
    for(i=0;i<m;i++){
      cin>>x>>y;
      b[x].set(y);
    }
    for(i=n;i>0;i--){
      for(j=n;j>0;j--)
        if(!ans[j]&&b[j].none()){
          ans[j]=i;
          for(int k=1;k<=n;k++)
            b[k].reset(j);
          break;
        }
      if(j<1) break;
    }
    if(i>0)
      cout<<-1<<endl;
    else{
      for(int i=1;i<=n;i++)
        cout<<ans[i]<<" ";
      cout<<endl;
    }
  }
  return 0;
}

By YOUSIKI

你可能感兴趣的:(POJ 3687 Labeling Balls)