ZOJ3358 Green Dam Girl
Green Dam Girl (GDG) became bankrupt recently, and watashi picked her up to his dorm. Some ZJU ICPC team members would like to support her.
There are n team members who would like to support her. A member will give GDG q RMB (Renminbi, the currency of China) at the k-th night when GDG lives in his dorm continuously without any moving, where:
- q = ai , if k = 1;
- q = bi , if k = 2;
- q = ci , if k ≥ 3.
GDG will get the money in the next morning.
Every afternoon, GDG can choose to move or not. But she has too much baggage to move all by herself. Luckily, she can turn to the member whose dorm she is currently in for help. Of course, it's not free -- GDG needs to bg (means treat) the member. The member will tell GDG whose dorm he can help her to move to and how much money she will cost correspondingly. Here are some notes:
- If GDG don't get enough money to bg, she can't move to the dorm directly;
- GDG can only ask the member whose dorm she is currently in for help;
- GDG can move more than once. So, in order to move to some dorm, GDG may need to bg many times.
At the 1st night, GDG lives in watashi's dorm without any money. How much money can GDG possess before the d-th night?
Input
There are multiple cases. For each case, the first line contains two integers, n (1 ≤ n ≤ 100) and d (1 ≤ d ≤ 100). There are 2*n lines next. The (2*i+2)-th and (2*i+3)-th lines describe the information of the i-th (0 ≤ i < n) member, and watashi is always the 0-th member.
The (2*i+2)-th line contains 3 integers, ai, bi and ci (0 ≤ ai, bi, ci ≤ 10000). The (2*i+3)-th line begins with an integer mi (0 ≤ mi < n), followed by mi pairs of integers. The j-th (0 ≤ j < mi) pair of integers, numj (0 ≤ numj < n and numj ≠ i) and bgmj (0 < bgmj ≤ 10000), indicates that the i-th member can help GDG to move to the numj-th member's dorm as long as she cost bgmj RMB to bg him. It's guaranteed that each numj is different from others.
Output
For each case, output the maximum amount of money GDG can possess before the d-th night in a single line.
Sample Input
3 6 1 1 1 1 1 1 2 2 2 1 2 2 3 3 3 0
Sample Output
9
原题地址:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3358
___________________________________________________________________________________________________________
题解:
绝对是非常邪恶的一道题
显然是dp,最一开始的想法是DP[I][J][K]表示第I天在第J个人家里,K取0,1,2表示连续住的情况。
由于一天到搬N次家,有向图中的先后顺序就乱了,不知道从哪个开始dp,所以就写了个记忆化,。
写着写着不知道怎么的又改成DP[I][J][K]表示第I天在第J个人家里,连续住了K天,(1<k<=j),结果就是超时了……
题解果然精妙,先FLOYED求搬到别人家的最短路,那么先后顺序就好定了,DP[I][J][K]表示第I天在第J个人家里,K取0,1,2表示连续住的情况。
每次可以选择搬,转移到dp[i][j'][0],或不搬,转移到dp[i][j][min(k + 1, 2)]。 这样前推后容易理解,K=2就表示连续住3天或3天以上。
如果DP[I][=MAX{DP[I-1]}这样推的话,就不怎么好理解了……
代码1 #include<stdio.h>
2 #include<memory.h>
3 #define oo 0xfffffff
4 int dp[101][101][3],map[101][101],mem[101][3];
5 int i,j,k,l,m,n,d,u,v,ans;
6 inline int max(int a,int b)
7 {
8 if (a>b) return a;
9 return b;
10 }
11 inline int min(int a,int b)
12 {
13 if (a>b) return b;
14 return a;
15 }
16 void work()
17 {
18 for (i=0;i<n;i++)
19 for (j=0;j<n;j++)
20 map[i][j]=oo;
21 for (i=0;i<n;i++)
22 {
23 scanf("%d%d%d",&mem[i][0],&mem[i][1],&mem[i][2]);
24 scanf("%d",&m);
25 for (j=1;j<=m;j++)
26 {
27 scanf("%d%d",&u,&v);
28 map[i][u]=v;
29 }
30 }
31 for (k=0;k<n;k++)
32 for (i=0;i<n;i++)
33 for (j=0;j<n;j++)
34 if (map[i][k]!=-1||map[k][j]!=-1)
35 if (map[i][k]+map[k][j]<map[i][j])
36 map[i][j]=map[i][k]+map[k][j];
37 for (i=0;i<n;i++)
38 for (j=1;j<=d;j++)
39 for (k=0;k<3;k++)
40 dp[i][j][k]=-oo;
41 dp[0][1][0]=0;
42 for (j=1;j<d;j++)
43 for (i=0;i<n;i++)
44 for (k=0;k<3;k++)
45 {
46 dp[i][j][k]+=mem[i][k];
47 dp[i][j+1][min(2,k+1)]=max(dp[i][j+1][min(2,k+1)],dp[i][j][k]);
48 for (l=0;l<n;l++)
49 if (map[i][l]!=-1&&dp[i][j][k]-map[i][l]>=0)
50 dp[l][j+1][0]=max(dp[l][j+1][0],dp[i][j][k]-map[i][l]);
51 }
52 ans=0;
53 for (i=0;i<n;i++)
54 for (k=0;k<3;k++)
55 ans=max(dp[i][d][k],ans);
56 printf("%d\n",ans);
57 }
58 int main()
59 {
60 while (scanf("%d%d",&n,&d)!=EOF)
61 {
62 work();
63 }
64 return 0;
65 }
66