codeforces 716d 图论加二分

参考自:http://www.bubuko.com/infodetail-1762450.html

题目大意:给你一副无向图,边有权值,初始权值>=0,若权值==0,则需要把它变为一个正整数(不超过1e18),现在问你有没有一种方法,

     使图中的边权值都变为正整数的时候,从 S 到 T 的最短路恰好等于 L。

     若没有输出 "NO",否则输出 "YES",同时输出新图中的所有边权值。

题解:显然将所有边值都设为1若最短路大于L则无解,所有边值设为INF最短路小于L则无解。

   其他情况一定是有解的。可以想象成将所有的边一次加一,如此循环操作,最短路必定会慢慢加一必定能够到达L;

   那么假设总共有x条权值不确定的边,假设先对第一条边操作,将其不断加一,每加一次跑一遍最短路,始终不能到达L则说明经过第一条边的路必定始终大于L,同理对接下来的边也如此操作。当然这样直接写会很复杂,可以用二分来模拟这个过程,具体就是代码中的cek()函数

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cmath>
  4 #include <iostream>
  5 #include <algorithm>
  6 #include <map>
  7 #include <vector>
  8 #include <queue>
  9 using namespace std;
 10 #define EPS 1e-10
 11 typedef long long ll;
 12 const int maxn = 1e4 + 10;
 13 const double INF = 1e9 +1.0;
 14 int n,m,l,s,t,cnt;
 15 int head[1010];
 16 double dis[1010],gra[1010][1010];
 17 vector<pair<int,int> >q;
 18 vector<int>q1;
 19 struct st1{
 20     int to,nxt,u;
 21     double w;
 22 }edge[maxn*2];
 23 void add(int u,int v,double w){
 24     edge[cnt].u = u;
 25     edge[cnt].to = v;
 26     edge[cnt].w = w;
 27     edge[cnt].nxt = head[u];
 28     cnt++;
 29 }
 30 int dijstra()
 31 {
 32     int i,j,pos=1;
 33     double min;
 34     int visit[1010];
 35     memset(visit,0,sizeof(visit));
 36     double inf = 1e15+1.0;
 37     for(i=0;i<n;++i)
 38         dis[i]= gra[s][i];
 39     visit[s]=1;
 40     dis[s]=0;
 41     for(i=0;i<n;i++)
 42     {
 43         min=inf;
 44         for(j=0;j<n;++j)
 45         {
 46             if(!visit[j]&&min>dis[j])
 47             {
 48                 min=dis[j];
 49                 pos=j;
 50             }
 51         }
 52         visit[pos]=1;
 53         for(j=0;j<n;++j)
 54         {
 55             if(!visit[j]&&dis[j]>dis[pos]+gra[pos][j]){
 56             dis[j]=dis[pos]+gra[pos][j];
 57 
 58             }
 59         }
 60     }
 61     //cout<<dis[t]<<endl;
 62     return dis[t];
 63 
 64 }
 65 int cek(ll sum){
 66     for(int i = 0;i < q.size();i++){
 67         int u = q[i].first,v = q[i].second;
 68         gra[u][v] = gra[v][u] = 1 + min(sum,1000000000ll);
 69         int x = q1[i];
 70         edge[x].w = gra[u][v];
 71         edge[x+1].w = gra[u][v];
 72         sum -= gra[u][v] - 1;
 73     }
 74     return dijstra();
 75 }
 76 int main(){
 77   //  freopen("in.txt","r",stdin);
 78     memset(head,-1,sizeof(head));
 79     scanf("%d%d%d%d%d",&n,&m,&l,&s,&t);
 80     int a,b;
 81     double c;
 82     for(int i = 0;i < n;i++)
 83         for(int j = i; j < n;j++){
 84             gra[i][j] = INF;
 85             gra[j][i] = INF;
 86         }
 87     for(int i = 1;i <= m;i++){
 88         scanf("%d%d%lf",&a,&b,&c);
 89         if(c == 0){
 90             q.push_back(make_pair(a,b));
 91             q1.push_back(cnt);
 92         }
 93         else{
 94             gra[a][b] = gra[b][a] = c;
 95         }
 96         add(a,b,c);
 97         add(b,a,c);
 98     }
 99     ll L = 0,r =(ll)q.size()*1e9;
100     if(cek(L) > l||cek(r) < l){
101       // cout<<cek(L)<<" "<<cek(r)<<" "<<l<<endl;
102         cout<<"NO"<<endl;
103         return 0;
104     }
105     while(L <= r){
106         ll mid = (L + r)/2;
107         int temp = cek(mid);
108         if(temp > l) r = mid;
109         else if(temp < l) L = mid + 1;
110         else break;
111     }
112     cout<<"YES"<<endl;
113     for(int i = 0;i <= 2*m - 2;i += 2)
114         printf("%d %d %0.f\n",edge[i].u,edge[i].to,edge[i].w);
115     return 0;
116 }

 

posted @ 2016-09-19 22:09  十目  阅读(494)  评论(0编辑  收藏  举报