区域赛的题目读着就是蛋疼,读到一半放弃了,不过今天重新拾起。
题意:有一个有向无自环的连通图,每个结点都有权值。现在有两艘船要从能到达任意结点的点出发(我的理解就是入度为零的点),直到出度为零的点,途中获得每个结点的权值(包括起点和终点)。现在这两艘船a希望得到更多的权值,另一艘b希望得到尽量少的权值。他们从起点开始,由a,b轮流领航(自然领航的人会走对自己有利的路),问到终点的权值能否满足要求。
思路:如果只有一艘船,那这个问题简化成如何获得更多或更少的权值,这类型的记忆化搜索做过一些。两艘船的话,用dp[i][0]表示船b以i为根结点最少能获得的权值;dp[i][1]表示船a以i为根结点最多能够获得的权值。。。 此时dp[i][] = v[i] + max(dp[u0][]..,.,.,.,..dp[un][]); 或者dp[i][] = v[i] + min(dp[u0][]..,.,.,.,..dp[un][]); 只需要用标记判断是谁在领航就行。
#include <cstdio> #include <cstring> #include <iostream> #include <vector> # define MAX 11111 using namespace std; int dp[MAX][2],v[MAX],deg[MAX]; int n,m,f; vector <int> edge[MAX]; void init() { memset(dp,0,sizeof(dp)); memset(deg,0,sizeof(deg)); for(int i=0; i<=11111; i++) { edge[i].clear(); } } int dfs(int v0,int cur) { if(dp[v0][cur%2] != 0) return dp[v0][cur%2]; int size = edge[v0].size(); if(size == 0) return v[v0]; int maxx = -1111111111,minn = 1111111111; for(int i=0; i<size; i++) { int u = edge[v0][i]; if(cur % 2 == 1) { maxx = max(maxx,dfs(u,cur+1)); } else { minn = min(minn,dfs(u,cur+1)); } } if(cur % 2 == 1) return dp[v0][cur%2] = maxx + v[v0]; else return dp[v0][cur%2] = minn + v[v0]; } int main() { int i,a,b; while(scanf("%d%d%d",&n,&m,&f)!= EOF) { init(); for(i=1; i<=n; i++) scanf("%d",&v[i]); for(i=1; i<=m; i++) { scanf("%d%d",&a,&b); edge[a].push_back(b); deg[b] ++; } int maxx = -1111111111; for(i=1; i<=n; i++) { if(! deg[i]) { maxx = max(maxx,dfs(i,1)); } } if(maxx >= f) printf("Victory\n"); else printf("Glory\n"); } return 0; }