BZOJ 3890 [Usaco2015 Jan]Meeting Time:拓扑图dp
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3890
题意:
给你一个有向图,n个点(n <= 100),m条边。
且所有的边都是从编号小的点指向编号大的点。
对于每条边i,Bessie要用c[i]的时间,Elsie要用d[i]的时间(c,d <= 100)。
Bessie和Elsie从1号点出发,向n号点走去,且两人都不会在路上停留。
问你使两人同时到达n点的最小时间。若不可能同时到达,输出"IMPOSSIBLE"。
题解:
表示状态:
bool f[i][j] and g[i][j]
分别表示Bessie和Elsie是否能够同时到达i号点,且花费时间为j。
找出答案:
min i with f[n][i] and g[n][i]
即两人同时到达n的最短时间
如何转移:
对于每个点i,一定是从某些编号比i小的点转移而来。
所以从小到大枚举点i,然后枚举到达时间j,再枚举i能够到达的下一个点dst。
顺推:
f[dst][j+c] |= f[i][j]
g[dst][j+d] |= g[i][j]
边界条件:
f[1][0] = g[1][0] = true
AC Code:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <vector> 5 #define MAX_N 105 6 #define MAX_T 10005 7 8 using namespace std; 9 10 struct Edge 11 { 12 int dest; 13 int c; 14 int d; 15 Edge(int _dest,int _c,int _d) 16 { 17 dest=_dest; 18 c=_c; 19 d=_d; 20 } 21 Edge(){} 22 }; 23 24 int n,m; 25 int ans=-1; 26 int f[MAX_N][MAX_T]; 27 int g[MAX_N][MAX_T]; 28 vector<Edge> edge[MAX_N]; 29 30 void read() 31 { 32 cin>>n>>m; 33 int a,b,c,d; 34 for(int i=0;i<m;i++) 35 { 36 cin>>a>>b>>c>>d; 37 edge[min(a,b)].push_back(Edge(max(a,b),c,d)); 38 } 39 } 40 41 void solve() 42 { 43 memset(f,false,sizeof(f)); 44 memset(g,false,sizeof(g)); 45 f[1][0]=true; 46 g[1][0]=true; 47 for(int i=1;i<=n;i++) 48 { 49 for(int j=0;j<MAX_T;j++) 50 { 51 if(f[i][j] || g[i][j]) 52 { 53 for(int k=0;k<edge[i].size();k++) 54 { 55 Edge temp=edge[i][k]; 56 f[temp.dest][j+temp.c]|=f[i][j]; 57 g[temp.dest][j+temp.d]|=g[i][j]; 58 } 59 } 60 } 61 } 62 for(int i=0;i<MAX_T;i++) 63 { 64 if(f[n][i] && g[n][i]) 65 { 66 ans=i; 67 break; 68 } 69 } 70 } 71 72 void print() 73 { 74 if(ans==-1) cout<<"IMPOSSIBLE"<<endl; 75 else cout<<ans<<endl; 76 } 77 78 int main() 79 { 80 read(); 81 solve(); 82 print(); 83 }