bzoj1003 trans DP
最初的印象是网络流之类的东西,但好像不是。
想了一下,没什么思路,就网上看了一下,有人说是DP,然后就自己想DP的做法,最开始想的状态是:dp[n][s] 第n天走s这条路,前n天最小的代价,但发现路径不好表示,并且m=20时s最大就是10^6级别了,所以放弃了这个状态。
打开题解,发现题解的状态不需要记录s,即dp[n]表示前n天最小的代价和,然后用一个辅助数组mdis[i][j]表示从第i天到第j天所有限制共同作用下的图的最短路。转移:
dp[i] = min( mdis[1][i]*i, dp[j]+mdis[j+1][i]*(i-j)+K | j in [1,i) }
的确很好,也很自然(对于一个最优解,必定是由一些“路径改变点”组成,而两个“路径改变点"之间走的一定是满足该区间限制下的最短路,我们每次只需要枚举最后一个路径改变点,就可以转移了)。有点像一个多决策问题(对于每一天,决策是改变或不改变路径)。
1 /************************************************************** 2 Problem: 1003 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:28 ms 7 Memory:860 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 #include <cstring> 12 #include <queue> 13 #include <vector> 14 #define maxn 110 15 #define maxm 25 16 #define inf 0x3f3f3f3f 17 using namespace std; 18 19 int n, m, e, K; 20 21 vector<int> g[maxm], wght[maxm]; 22 bool gave[maxm][maxn]; 23 bool cave[maxm]; 24 25 int mdis[maxn][maxn]; 26 int dis[maxm]; 27 bool done[maxm]; 28 int dp[maxn]; 29 30 31 void input() { 32 scanf( "%d%d%d%d", &n, &m, &K, &e ); 33 for( int i=1,u,v,w; i<=e; i++ ) { 34 scanf( "%d%d%d", &u, &v, &w ); 35 g[u].push_back(v); 36 g[v].push_back(u); 37 wght[u].push_back(w); 38 wght[v].push_back(w); 39 } 40 memset( gave, 1, sizeof(gave) ); 41 int d; 42 scanf( "%d", &d ); 43 for( int i=1,u,a,b; i<=d; i++ ) { 44 scanf( "%d%d%d", &u, &a, &b ); 45 for( int i=a; i<=b; i++ ) 46 gave[u][i] = false; 47 } 48 } 49 50 struct Stat { 51 int u, dis; 52 Stat( int u, int dis ):u(u),dis(dis){} 53 bool operator<( const Stat & b ) const { 54 return dis>b.dis; 55 } 56 }; 57 int dijstra( int s, int d ) { 58 priority_queue<Stat> hp; 59 memset( done, false, sizeof(done) ); 60 memset( dis, 0x3f, sizeof(dis) ); 61 dis[s] = 0; 62 hp.push( Stat(s,0) ); 63 while( !hp.empty() ) { 64 int u = hp.top().u; 65 hp.pop(); 66 if( done[u] ) continue; 67 done[u] = true; 68 if( u==d ) return dis[d]; 69 for( int t=0; t<g[u].size(); t++ ) { 70 int v = g[u][t]; 71 int w = wght[u][t]; 72 if( !cave[v] ) continue; 73 if( dis[v]>dis[u]+w ) { 74 dis[v]=dis[u]+w; 75 hp.push( Stat(v,dis[v]) ); 76 } 77 } 78 } 79 return inf; 80 } 81 void prep() { 82 memset( mdis, 0x3f, sizeof(mdis) ); 83 for( int i=1; i<=n; i++ ) { 84 memset( cave, 1, sizeof(cave) ); 85 for( int j=i; j<=n; j++ ) { 86 for( int u=1; u<=m; u++ ) 87 cave[u] &= gave[u][j]; 88 mdis[i][j] = dijstra(1,m); 89 } 90 } 91 } 92 void work() { 93 for( int i=1; i<=n; i++ ) { 94 if( mdis[1][i]!=inf ) 95 dp[i] = mdis[1][i]*i; 96 else dp[i]=inf; 97 for( int j=1; j<i; j++ ) 98 if( mdis[j+1][i]!=inf ) 99 dp[i] = min( dp[i], dp[j]+mdis[j+1][i]*(i-j)+K ); 100 } 101 printf( "%d\n", dp[n] ); 102 } 103 int main() { 104 input(); 105 prep(); 106 work(); 107 }