此处有目录↑
http://acm.hdu.edu.cn/showproblem.php?pid=4571
1 4 4 22 0 3 1 1 1 1 5 7 9 12 0 1 10 1 3 10 0 2 10 2 3 10
Case #1: 21
第一反应就是Floyd处理出任意两点间最短距离,然后dfs
结果没有记忆化TLE了好久,然后又往DP想,发现可解,不过还是觉得dfs能过,找了一些dfs解法的题解,发现大神都是加上记忆化(不加记忆化的剪纸根本没用,血的教训),并且添加虚拟起点和终点以消除特殊情况。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAXN=105; int n,m,t,sta,des,ans,STA,DES; int dis[MAXN][MAXN],c[MAXN],s[MAXN],dp[MAXN][305]; void dfs(int cur,int cost,int satis) {//dfs(cur,cost,satis)表示当前已经到达cur点且已参观 if(cost>t||satis<dp[cur][cost]) return ; dp[cur][cost]=satis; if(cost+dis[cur][DES]<=t) { for(int i=0;i<=n;++i) { if(cur==STA||s[i]>s[cur]) { dfs(i,cost+dis[cur][i]+c[i],satis+s[i]); } } } } int main() { int W,u,v,l,kase=0; scanf("%d",&W); while(kase<W) { memset(dis,0x3f,sizeof(dis)); scanf("%d%d%d%d%d",&n,&m,&t,&sta,&des); STA=n+1;//添加一个必定参观的虚拟起点 DES=n;//添加一个必定参观的虚拟终点 c[STA]=c[DES]=s[STA]=0; s[DES]=MAXN;//虚拟终点满意度为MAXN,保证虚拟终点一定能被参观 for(int i=0;i<n;++i) scanf("%d",c+i); for(int i=0;i<n;++i) scanf("%d",s+i); while(m-->0) { scanf("%d%d%d",&u,&v,&l); if(dis[u][v]>l) dis[u][v]=dis[v][u]=l; } for(int k=0;k<n;++k) for(int i=0;i<n;++i) for(int j=0;j<n;++j) dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]); for(int i=0;i<n;++i) { dis[STA][i]=dis[sta][i]; dis[i][DES]=dis[i][des]; } dis[STA][DES]=dis[sta][des]; dis[STA][sta]=dis[des][DES]=0; ans=MAXN; memset(dp,0,sizeof(dp)); dfs(STA,0,0); for(int j=0;j<=t;++j) ans=max(ans,dp[DES][j]); printf("Case #%d:\n%d\n",++kase,ans-MAXN); } return 0; }
最后还是想用DP做一下,dp数组无脑初始化,又浪费好长时间找错
前面同解法一
dp[i][j]表示从起始点到i点并且参观了i点时,用时为j的最大满意度和
采用“我为人人”的方法进行状态转移,所以每次选取s值最小的点进行状态转移
为了降低复杂度,按照s值升序排序,最终复杂度为O(n*n*t)
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAXN=105; struct Node { int i,s; bool operator < (const Node& a) const { return s<a.s; } }p[MAXN]; int n,m,t,sta,des,ans,STA,DES,len; int dis[MAXN][MAXN],c[MAXN],s[MAXN],dp[MAXN][305]; int main() { int W,u,v,l,kase=0,cur,nxt,cost; scanf("%d",&W); while(kase<W) { memset(dis,0x3f,sizeof(dis)); scanf("%d%d%d%d%d",&n,&m,&t,&sta,&des); STA=n+1;//添加一个必定参观的虚拟起点 DES=n;//添加一个必定参观的虚拟终点 c[STA]=c[DES]=len=0; s[DES]=MAXN;//虚拟终点满意度为MAXN,保证虚拟终点一定能被参观 p[len].i=STA; p[len++].s=s[STA]=-1; p[len].i=DES; p[len++].s=s[DES]; for(int i=0;i<n;++i) scanf("%d",c+i); for(int i=0;i<n;++i) { scanf("%d",s+i); p[len].i=i; p[len++].s=s[i]; } sort(p,p+len); while(m-->0) { scanf("%d%d%d",&u,&v,&l); if(dis[u][v]>l) dis[u][v]=dis[v][u]=l; } for(int k=0;k<n;++k) for(int i=0;i<n;++i) for(int j=0;j<n;++j) dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]); for(int i=0;i<n;++i) { dis[STA][i]=dis[sta][i]; dis[i][DES]=dis[i][des]; } dis[STA][DES]=dis[sta][des]; dis[STA][sta]=dis[des][DES]=0; memset(dp,-1,sizeof(dp));//刚开始赋值为0,又调试好久,最后终于意识到有些状态是无效的 dp[STA][0]=0; for(int i=0;i<len;++i) { cur=p[i].i; for(int j=0;j<=t;++j) { if(dp[cur][j]!=-1) { for(int k=i+1;k<len;++k) { nxt=p[k].i; cost=dis[cur][nxt]+j+c[nxt]; if(s[nxt]>s[cur]&&cost<=t) { dp[nxt][cost]=max(dp[nxt][cost],dp[cur][j]+s[nxt]); } } } } } ans=MAXN; for(int j=0;j<=t;++j) ans=max(ans,dp[DES][j]); printf("Case #%d:\n%d\n",++kase,ans-MAXN); } return 0; }