原题:UVA 1172 http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3613
动态规划问题。
定义: dp[i] = 右岸前i个村庄(m岸)能够与左岸(n岸)不交叉匹配的最大权值和最小桥数 (用pair<int,int> 维护两个值)
方程:
dp[i].first = max(dp[i].first,dp[i-1].first(i>=1)+cost1[i]+cost2[j]) when 左岸的i与右岸的j相匹配
dp[i].second = dp[i-1].second(i>=1)+1 (if 上面dp[i].first更小)
从后往前枚举,然后从前往后更新。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <string> #include <vector> #include <map> using namespace std; #define N 1007 string os1[N],os2[N]; int osind1[N],osind2[N]; int cost1[N],cost2[N]; pair<int,int> dp[N]; map<string,int> mp; int main() { int t,i,j,n,m; int now; string tmp; scanf("%d",&t); while(t--) { now = 1; mp.clear(); scanf("%d",&n); for(i=1;i<=n;i++) { cin>>tmp>>os1[i]>>cost1[i]; if(!mp[os1[i]]) mp[os1[i]] = now++; osind1[i] = mp[os1[i]]; } scanf("%d",&m); for(i=1;i<=m;i++) { cin>>tmp>>os2[i]>>cost2[i]; if(!mp[os2[i]]) mp[os2[i]] = now++; osind2[i] = mp[os2[i]]; } int maxi = max(n,m); for(i=0;i<=maxi;i++) dp[i] = make_pair(0,0); for(i=1;i<=n;i++) { for(j=m;j>=1;j--) { if(osind1[i] != osind2[j]) continue; int k,num; if(j >= 2) { k = dp[j-1].first + cost1[i] + cost2[j]; num = dp[j-1].second + 1; } else { k = cost1[i] + cost2[j]; num = 1; } if(dp[j].first < k) { dp[j].first = k; dp[j].second = num; } else if(dp[j].first == k) dp[j].second = min(dp[j].second,num); } for(j=2;j<=m;j++) { if(dp[j].first < dp[j-1].first) dp[j] = dp[j-1]; else if(dp[j].first == dp[j-1].first && dp[j].second > dp[j-1].second) dp[j] = dp[j-1]; } } printf("%d %d\n",dp[m].first,dp[m].second); } return 0; }