Topcoder WarTransportation 最短路转移dp

题目链接

方法一

 

  这道题的题意真的难理解,想了很久都没懂什么叫最小值最大......

  读完题一定要看样例!

  题目可以理解为:有甲要走最短路,乙在甲走到某一顶点v时可以删去一条v----->u的边,两人博弈,甲走的路最短为多少?

  分析一下数据范围可以发现n≤100,m≤500,O(n³)的算法都可以过

  我们可以先预处理出对于每一顶点V,当甲走到V时,乙去掉一条V的出边,此时甲从V到2的最短路长,记为bad[v]

  dp[v]为v的子图中删去一条边甲可以走的最短路

    ①删去一条v的出边

    ②删去v的子图中的其它出边

  所以dp[v]=max{bad[v],min{dp[u]+cost(u,v)|v到u有边} }

  可以通过最短路转移

  复杂度O(n log n)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define F first
 4 #define S second
 5 struct     WarTransportation
 6 {
 7     vector<pair<int,int> >nei[105],nei2[105];
 8     int bad[105];
 9     bool vis[105];
10     int dijdis[105],n;
11     int dij(int st,int cant)
12     {
13         for(int i=0;i<104;i++) dijdis[i]=1e9;
14         memset(vis,0,sizeof vis);
15         dijdis[st]=0;
16         priority_queue<pair<int,int> > q;
17         q.push(make_pair(0,st));
18         while(!q.empty())
19         {
20             pair<int,int> tmp=q.top();
21             q.pop();
22             if(vis[tmp.S]) continue;
23             tmp.F=-tmp.F;            
24             int v=tmp.S;
25             vis[v]=1;
26             if(tmp.S==1) return dijdis[1];
27             for(int i=0;i<nei[v].size();i++)
28             {
29                 if(v==st&&i==cant) continue;                
30                 int u=nei[v][i].F,cost=dijdis[v]+nei[v][i].S;
31                 if(cost>=dijdis[u]) continue;
32                 dijdis[u]=cost;
33                 q.push(make_pair(-cost,u));
34             }
35         }
36         //这里要返回inf 
37         return 1e9;
38     }
39     void getbad()
40     {
41         for(int i=0;i<n;i++)
42         {
43             int fir=0;
44             for(int j=0;j<nei[i].size();j++)
45             {
46                 int x=dij(i,j);
47                 if(x>fir) fir=x;
48             } 
49             bad[i]=fir;
50         }
51     }
52     int dp[105];
53     int messenger(int yy,vector<string> v)
54     {
55         n=yy;
56         int m;
57         stringstream ss;
58         //要熟悉stringstream的用法! 
59         for(int i=0;i<v.size();i++)
60         {
61             ss<<v[i];
62         }int x,y,co;
63         for(;ss>>x>>y>>co;)
64         {
65             m++;
66             x--;y--;
67             nei[x].push_back(make_pair(y,co));
68             nei2[y].push_back(make_pair(x,co));
69             char c;
70             ss>>c;
71         }
72         getbad();
73         memset(dp,-1,sizeof dp);
74         priority_queue<pair<int,int> >q;
75         q.push(make_pair(-bad[1],1));
76         for(int i=0;i<104;i++)dp[i]=2e9;
77         dp[1]=0;
78         memset(vis,0,sizeof vis);
79         while(!q.empty())
80         {
81             pair<int,int>tmp=q.top();
82             q.pop();
83             if(vis[tmp.S]) continue;
84             int v=tmp.S;
85             vis[v]=1;
86             for(int i=0;i<nei2[v].size();i++)
87             {
88                 int u=nei2[v][i].F,cost=max(bad[u],nei2[v][i].S+dp[v]);
89                 if(cost>=dp[u]) continue;
90                 dp[u]=cost;
91                 q.push(make_pair(-cost,u));
92             }
93         }
94         return (dp[0]<1e9)?dp[0]:-1;
95     }
96 };

 

方法二

  要使最小值最大,我们也可以考虑二分答案。

  可以二分在最坏情况下,最短路能不能小于T

  直接跑最短路,能够转移的条件为dist[v]+cost(v,u)+bad[u]<=T&&dist[v]+cost(v,u)<dist[u]

  复杂度O(n logn)

  1 typedef int             vert;
  2 typedef int             cost;
  3 typedef pair<cost,vert> edge;
  4 typedef vector<edge>    edges;
  5 typedef vector<edges>   graph;
  6 
  7 static const cost INF   = 0x12345678; // large enough but INF+INF<2^31
  8 static const vert START = 0;
  9 static const vert GOAL  = 1;
 10 
 11 class WarTransportation { public:
 12    int messenger(int n, vector <string> highways) 
 13    {
 14       return solve( parse(n, highways) );
 15    }
 16 
 17    graph parse(int n, vector <string> highways)
 18    {
 19       graph G(n);
 20 
 21       string hi = accumulate(highways.begin(), highways.end(), string());
 22       for(int i=0; i<hi.size(); )
 23       {
 24          int k = hi.find(',', i);
 25          if( k == string::npos ) k = hi.size();
 26 
 27          int a, b, c;
 28          stringstream(hi.substr(i,k-i)) >> a >> b >> c;
 29          G[a-1].push_back( edge(c,b-1) );
 30 
 31          i = k+1;
 32       }
 33 
 34       return G;
 35    }
 36 
 37    int solve( const graph& G )
 38    {
 39       // Suppose you reached the city "v", and found there the most critical load is broken.
 40       // How long will it take a detour to the GOAL?  It's ukai[v]!
 41 
 42       vector<cost> ukai;
 43       for(int v=0; v<G.size(); ++v)
 44          ukai.push_back( ukaiDist(G,v) );
 45 
 46       // Compute the least T such that:
 47       //   we get to the GOAL, making the worst case time <= T?
 48 
 49       cost L=0, R=99999999;
 50       if( !reachable(G, ukai, R) ) return -1;
 51       if(  reachable(G, ukai, L) ) return 0;
 52 
 53       // We can when T=R, and cannot T=L. 
 54       // That is, T in (L, R]. Now let's binary-search!
 55 
 56       while( R-L>1 )
 57          (reachable(G, ukai, (L+R)/2) ? R : L) = (L+R)/2;
 58       return R;
 59    }
 60 
 61    cost ukaiDist( const graph& G, vert v )
 62    {
 63       if( v == GOAL )        return 0;
 64       if( G[v].size() == 0 ) return INF;
 65 
 66       cost worst = 0;
 67       for(int f=0; f<G[v].size(); ++f) // f : broken road
 68       {
 69          priority_queue< edge, vector<edge>, greater<edge> > Q;
 70          set<vert> V;
 71          V.insert(v);
 72          for(int i=0; i<G[v].size(); ++i) // push all loads from v, except f
 73             if( i != f )
 74                Q.push( G[v][i] );
 75          worst = max( worst, dijkstra(G,Q,V) ); // start dijkstraing
 76       }
 77       return worst;
 78    }
 79 
 80 
 81    bool reachable( const graph& G, const vector<cost>& ukai, cost ukaiLimit )
 82    {
 83       priority_queue< edge, vector<edge>, greater<edge> > Q;
 84       set<vert> V;
 85       Q.push( edge(0,START) );
 86       return dijkstra(G, Q, V, ukai, ukaiLimit) != INF;
 87    }
 88 
 89    cost dijkstra( const graph& G,
 90       priority_queue< edge, vector<edge>, greater<edge> >& Q, set<vert>& V,
 91       const vector<cost>& ukai=vector<cost>(), cost ukaiLimit=-1
 92    ) {
 93       while( !Q.empty() )
 94       {
 95          // pop
 96          cost c = Q.top().first;
 97          vert v = Q.top().second;
 98          Q.pop();
 99 
100          // check
101          if( V.count(v) || (ukaiLimit>=0 && c+ukai[v]>ukaiLimit) )
102             continue;
103          if( v == GOAL )
104              return c;
105          V.insert(v);
106 
107          // next
108          for(int i=0; i<G[v].size(); ++i)
109             if( !V.count(G[v][i].second) )
110                Q.push( edge(c+G[v][i].first, G[v][i].second) );
111       }
112       return INF;
113    }
114 };
posted @ 2018-07-13 14:43  双零  阅读(181)  评论(0编辑  收藏  举报