[HNOI2009]最小圈

~~~题面~~~

题解:

0/1分数规划的题。

不知道0/1分数规划的可以先看看我的简单介绍: 0/1分数规划

具体的还是来看题目吧。

这个题面应该还是比较直白的,

就是每条边有a[i]=权值,b[i]=1

的最小值,

其中选择的边必须构成一个环

所以我们修改权值为的左半部分

然后用spfa判负环即可

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define R register int
  4 #define AC 3100
  5 #define ACway 11000
  6 #define eps 1e-9
  7 int n,m;
  8 int date[ACway],Next[ACway],Head[AC],tot;
  9 double mid,maxn,minn;
 10 double length[ACway],Size[ACway],dis[AC];
 11 bool vis[AC],flag;
 12 /*01分数规划emmm。。。
 13 相当于代价为0了,
 14 二分答案,然后将边权统一降低mid,因为是<=0,所以直接找负环就可以了*/
 15 
 16 inline int read()
 17 {
 18     int x=0;char c=getchar();
 19     while(c > '9' || c < '0') c=getchar();
 20     while(c >= '0' && c <='9') x=x*10+c-'0',c=getchar();
 21     return x;
 22 }
 23 
 24 inline void add(int f,int w,double S)
 25 {
 26     date[++tot]=w,Next[tot]=Head[f],Head[f]=tot,length[tot]=S;
 27 }
 28 
 29 inline void upmax(double &a,double b)
 30 {
 31     if(b > a) a = b;
 32 }
 33 
 34 inline void upmin(double &a,double b)
 35 {
 36     if(b < a) a = b;
 37 }
 38 
 39 void pre()
 40 {
 41     int a,b;double c;
 42     n=read() , m=read();
 43     maxn = -INT_MAX,minn = INT_MAX;
 44     for(R i=1;i<=m;i++)
 45     {
 46         a=read(),b=read(),scanf("%lf",&c);
 47         add(a,b,c);
 48         upmax(maxn,c);
 49         upmin(minn,c);
 50     }
 51 }
 52 
 53 void spfa(int x)//dfs版spfa判负环
 54 {
 55     int now;
 56     vis[x]=true;
 57     for(R i=Head[x]; i ;i=Next[i])
 58     {
 59         now=date[i];
 60         if(dis[now] > dis[x] + Size[i])
 61         {
 62             if(vis[now])
 63             {
 64                 flag = true;
 65                 break;//如果是return 的话就没办法回溯了,那样就会误判
 66             }
 67             dis[now] = dis[x] + Size[i];
 68             spfa(now);
 69         }
 70         if(flag) break;//也许可以剪枝????
 71     }
 72     vis[x]=false;
 73 }
 74 
 75 void init()//重置边权
 76 {
 77     flag=false;
 78     for(R i=1;i<=tot;i++)
 79         Size[i] = length[i] - mid;//边权修改为真实权值 - 当前答案
 80     memset(dis,0,sizeof(dis));
 81     memset(vis,0,sizeof(vis));
 82 }
 83 
 84 void half()
 85 {
 86     double l=minn,r=maxn;
 87     while(r - l > eps)
 88     {
 89         mid=(l + r) / 2.0;
 90         init();
 91         for(R i=1;i<=n;i++)
 92         {
 93             if(flag) break;
 94             spfa(i);
 95         }
 96         if(flag) r = mid;
 97         else l = mid + eps;
 98     }
 99     printf("%.8lf\n",l);
100 }
101 
102 int main()
103 {
104 //    freopen("in.in","r",stdin);
105     pre();
106     half();
107 //    fclose(stdin);
108     return 0;
109 }

 

posted @ 2018-06-06 09:59  ww3113306  阅读(150)  评论(0编辑  收藏  举报
知识共享许可协议
本作品采用知识共享署名-非商业性使用-禁止演绎 3.0 未本地化版本许可协议进行许可。