USACO 2002 February
2014-08-29 20:32
344 查看
今天刷了刷USACO 2002 February,从年份上看题目已经很老了。。可是我还是刷不动。。。
只能说是自己太弱了 还是需要多加练习才是啊。
今天只做了三道题。。其中有一道题是刚才补得。。学习了一下树形dp。。实在是惭愧的很。。
POJ 1949 - [b]Chores(这是我做的这套题里的第一道题目)[/b]
题目大意:给你N个任务,这些任务是可以并行开始的,但是部分任务需要完成它的前置任务后才能去做,问你完成所有任务的最短时间
题目分析:可以把每个任务当做顶点,再从前置任务到后置任务之间连边,就形成了一个AOV(Active on vertex)网,然后数据结构课上老师说过,我们可以先对这个AOV网进行拓扑排序,然后再对这个网进行dp,最后求得整个问题的解。
dp[i]表示完成第i个任务需要的最短时间
则有 dp[son[i]] = min{ dp[i]+time[son[i]] }
写的时候竟然发现拓扑排序不会写!!好吧。。看来真得需要多练练了。
这道题目我偷了个懒,我把所有没有前置任务的任务都给了个前置任务:0号任务,我把所有没有后置任务的任务都给了个后置任务:N+2号任务,这样就能够保证只形成了一个AOV网,不用去分开计算每个AOV网的值。
代码写的略挫。。还WA了几记在初始化上。。自己真是菜。。
POJ 1951 - Extra Krunch
题目大意:给你一个字符串,让你去除重复出现的字母以及AEIOU这5个字母,还有多余的空格。
题目分析:题目很简单,照着做就行了,详见代码,但是要注意一点:后面如果出现了句点,那么之前是不可以有空格的。
代码:
POJ 1947 - Rebuilding Roads
题目大意:给你一棵有n个节点的树,问你从中获得一棵有p个节点的子树最少需要去掉几条边。
题目分析:这是我做的第一道树形dp的题目,之前从来都没做过,也是看了题解才明白的。
我们定义dp状态:dp[u][j]表示以根节点为u的子树中找出j个节点的子树需要去掉的最少的边。
那么这就有个dp转移方程了,我们假设v是u的儿子节点,那么dp[u][j] = dp[v1][k1]+dp[v2][k2]+dp[v3][k3]+...+dp[vn][kn],其中k1+k2+k3+...+kn = j
这个式子显然需要优化,于是有:dp[u][j] = dp[v1][k1]+dp[v2][k2]+...+dp[v i-1][k i-1]+dp[v i+1][k i+1]+...+dp[vn][kn]+dp[vi][ki],其中k1+k2+...+k i-1+k i+1 + kn = j-ki
于是有dp[u][j] = dp[v1][k1]+dp[v2][k2]+...+dp[v i-1][k i-1]+dp[vi][0]+dp[v i+1][k i+1]+...+dp[vn][kn]+dp[vi][ki]-dp[vi][0]
因为dp[u][j-k] = dp[v1][s1]+dp[v2][s2]+...dp[vn][sn] 其中s1+s2+...+sn=j-k,因此上式可以表示成为dp[u][j] = dp[u][j-k]+dp[vi][ki]-dp[vi][0]
因为dp[vi][0]始终为1(我们不要这整棵子树,只需要剪掉vi与u连的边就行了
因此整个dp方程为:dp[u][j] = dp[u][j-k]+dp[vi][ki]-1
见代码:
只能说是自己太弱了 还是需要多加练习才是啊。
今天只做了三道题。。其中有一道题是刚才补得。。学习了一下树形dp。。实在是惭愧的很。。
POJ 1949 - [b]Chores(这是我做的这套题里的第一道题目)[/b]
题目大意:给你N个任务,这些任务是可以并行开始的,但是部分任务需要完成它的前置任务后才能去做,问你完成所有任务的最短时间
题目分析:可以把每个任务当做顶点,再从前置任务到后置任务之间连边,就形成了一个AOV(Active on vertex)网,然后数据结构课上老师说过,我们可以先对这个AOV网进行拓扑排序,然后再对这个网进行dp,最后求得整个问题的解。
dp[i]表示完成第i个任务需要的最短时间
则有 dp[son[i]] = min{ dp[i]+time[son[i]] }
写的时候竟然发现拓扑排序不会写!!好吧。。看来真得需要多练练了。
这道题目我偷了个懒,我把所有没有前置任务的任务都给了个前置任务:0号任务,我把所有没有后置任务的任务都给了个后置任务:N+2号任务,这样就能够保证只形成了一个AOV网,不用去分开计算每个AOV网的值。
代码写的略挫。。还WA了几记在初始化上。。自己真是菜。。
#include <cstdio> #include <vector> #include <cstring> using namespace std; int N,time[10100]; vector<int> G[10100]; int vis[10100],topo[10100],ptr_t; int dp[10100]; //此处是拓扑排序用到的dfs bool dfs(int u){ vis[u] = -1; for(int v=0;v<G[u].size();v++){ if(vis[G[u][v]]<0 ) return false; if(!vis[G[u][v]]) dfs(G[u][v]); } topo[--ptr_t] = u; vis[u] = 1; return true; } //拓扑排序的启动函数,结果存在topo数组里 void topo_sort(){ for(int i=0;i<N;i++){ if(!vis[i]){ dfs(i); } } } int main() { while(scanf("%d",&N)!=EOF){ memset(vis,0,sizeof(vis)); memset(dp,0,sizeof(dp)); memset(topo,0,sizeof(topo)); memset(time,0,sizeof(time)); for(int i=0;i<10100;i++)G[i].clear(); for(int i=1;i<=N;i++){ int nn; scanf("%d%d",&time[i],&nn); for(int j=0;j<nn;j++){ int t; scanf("%d",&t); G[t].push_back(i); } if(nn==0){ G[0].push_back(i); //给所有没有前置任务的任务指定前置任务0 } } for(int i=1;i<=N;i++){ //给所有没有后置任务的任务指定后置任务N+1 if(G[i].size()==0){ G[i].push_back(N+1); } } N+=2; //多了两个任务 ptr_t = N; topo_sort(); dp[0] = 0; for(int i=0;i<N;i++){ int u = topo[i]; for(int w = 0; w<G[u].size();w++){ int v = G[u][w]; dp[v] = max(dp[v],dp[u]+time[v]); } } printf("%d\n",dp[N-1]); } return 0; }
POJ 1951 - Extra Krunch
题目大意:给你一个字符串,让你去除重复出现的字母以及AEIOU这5个字母,还有多余的空格。
题目分析:题目很简单,照着做就行了,详见代码,但是要注意一点:后面如果出现了句点,那么之前是不可以有空格的。
代码:
#include <cstdio> #include <vector> #include <cstring> #include <cctype> using namespace std; char s[1000]; bool has[30]; char ans[1000]; int getNum(char c){ if(c<='Z'&&c>='A') return c-'A'; return 26; } void init(){ has['A'-'A'] = has['E'-'A'] = has['I'-'A'] = has['O'-'A'] = has['U'-'A'] = true; } int main(){ while(gets(s)){ memset(has,0,sizeof(has)); memset(ans,0,sizeof(ans)); init(); int ptr = 0; int len = strlen(s); bool flag = true; for(int i=0;i<len;i++){ int id; if(isalpha(s[i])){ id = getNum(s[i]); if(!has[id]){ has[id] = true; ans[ptr++] = s[i]; flag = false; } } else if(isspace(s[i])){ if(!flag){ ans[ptr++] = s[i]; } flag = true; } else { ans[ptr++] = s[i]; flag = false; } } if(ans[ptr-1]=='.'&&ans[ptr-2]==' '){ ans[ptr-2] = '.'; ans[ptr-1] = '\0'; ptr--; } for(int i=ptr-1;i>=0;i--){ if(ans[i]!=' ') break; ans[i] = '\0'; } puts(ans); } return 0; }
POJ 1947 - Rebuilding Roads
题目大意:给你一棵有n个节点的树,问你从中获得一棵有p个节点的子树最少需要去掉几条边。
题目分析:这是我做的第一道树形dp的题目,之前从来都没做过,也是看了题解才明白的。
我们定义dp状态:dp[u][j]表示以根节点为u的子树中找出j个节点的子树需要去掉的最少的边。
那么这就有个dp转移方程了,我们假设v是u的儿子节点,那么dp[u][j] = dp[v1][k1]+dp[v2][k2]+dp[v3][k3]+...+dp[vn][kn],其中k1+k2+k3+...+kn = j
这个式子显然需要优化,于是有:dp[u][j] = dp[v1][k1]+dp[v2][k2]+...+dp[v i-1][k i-1]+dp[v i+1][k i+1]+...+dp[vn][kn]+dp[vi][ki],其中k1+k2+...+k i-1+k i+1 + kn = j-ki
于是有dp[u][j] = dp[v1][k1]+dp[v2][k2]+...+dp[v i-1][k i-1]+dp[vi][0]+dp[v i+1][k i+1]+...+dp[vn][kn]+dp[vi][ki]-dp[vi][0]
因为dp[u][j-k] = dp[v1][s1]+dp[v2][s2]+...dp[vn][sn] 其中s1+s2+...+sn=j-k,因此上式可以表示成为dp[u][j] = dp[u][j-k]+dp[vi][ki]-dp[vi][0]
因为dp[vi][0]始终为1(我们不要这整棵子树,只需要剪掉vi与u连的边就行了
因此整个dp方程为:dp[u][j] = dp[u][j-k]+dp[vi][ki]-1
见代码:
#include <cstdio> #include <algorithm> #include <cstring> #include <vector> using namespace std; #define INF 0x3f3f3f3f int dp[200][200]; vector<int> G[200]; int n,p; void dfs(int u){ if(G[u].size()==0){ // 叶子节点上,如果只保留叶子节点则不需要剪掉任何一条边 dp[u][1] = 0; return; } for(int i = 0;i < G[u].size(); i++){ int v = G[u][i]; dfs(v); } dp[u][1] = G[u].size(); for(int i=0;i<G[u].size();i++){ int v = G[u][i]; for(int j=p;j>=2;j--){ for(int k=1;k<=j;k++){ dp[u][j] = min(dp[u][j],dp[u][j-k]+dp[v][k]-1); } } } } int main(){ while(scanf("%d%d",&n,&p)!=EOF){ for(int i=0;i<200;i++) G[i].clear(); memset(dp,INF,sizeof(dp)); for(int i=0;i<n-1;i++){ int a,b; scanf("%d%d",&a,&b); G[a].push_back(b); } dfs(1); //答案是首先整棵树的根节点得到的值 int ans = dp[1][p]; //再来是每个以每个节点保留p个节点要剪掉的边,另外需要剪掉该节点与其父亲节点之间的边 for(int i=2;i<=n;i++){ ans = min(ans,dp[i][p]+1); } printf("%d\n",ans); } return 0; }
相关文章推荐
- 【USACO 2002 February】BUY LOW,BUY LOWER 低价购买
- BSOJ: 1625 【USACO 2002 February Green】重建道路
- usaco 月赛 2008 February Eating Together 题解
- Bsoj: 3696 -- 【USACO 2012 February Gold】附近的奶牛
- USACO 2017 February Gold
- 【USACO】2018 February Contest, Platinum题解
- 【USACO 2013 February Gold】旅行线路
- [USACO2002][poj1944]Fiber Communications(枚举)
- 树状动规 USACO Feb 2002 Rebuilding Roads 重建道路
- 【USACO 2007 February Silver】农场派对
- 【USACO 2013 February Gold】出租车
- [USACO2002][poj1945]Power Hungry Cows(启发式搜索)
- [USACO2002][poj1946]Cow Cycling(dp)
- 【USACO】2002 Feb Cow Cycling 奶牛赛车
- USACO2014FebruarySilver Auto-Complete
- [USACO2015February,Bronze] Problem1.Censoring(Bronze)
- [USACO2002][poj1947]Rebuilding Roads(树形dp)
- USACO2014FebruarySilver Secret Code
- [USACO2015February,Bronze] Problem2.COW
- 【贪心】[USACO 2015 February Contest, Gold]Circular Barn