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 }
View Code
posted @ 2015-02-16 14:20  idy002  阅读(198)  评论(0编辑  收藏  举报