ZOJ3206 Disaster Area Reconstruction ZOJ 3211 Dream City ZOJ 3212 K-Nice
2014-03-16 21:26
260 查看
省赛前热身做的题目,有难度的做出来的 放出来一下,印象更深刻,
在此打个小广告,都说咱们信息学院的不会享受生活不文雅,那么在此给一篇文章:让大家陶冶陶冶情操哈哈哈 http://www.sanwen.net/subject/3628849/
先来3206这道题目跟队友一起讨论WA了挺多把做出来的,题意是给你N个村庄,M条道路,道路是单向的,让你再建一条道路,使得这个图的连通分量最大,同时请输出最大连通分量 和 你所建的道路,
一开始完全想错,想到树链剖分,后来想暴力,看直接不行 就先进行强连通缩点,缩点完成后用DFS来进行查找,可惜超时,最后因为DFS发现有某些部分是重合查找,所有有些部分查找以后是可以递归返回值的,那么就是有递推的意思了,于是想到了树状DP,于是开始用树状DP, WA了有七把吧,给出代码
总体思路就是强连通缩点,然后进行树状DP
接下来3211
这是一道DP的题目,
意思是 给你N棵树,M天时间,一天砍一棵树,如果你有一天不砍,那么以后就不能再砍了,树是摇钱树,所以一开始树上长了一些金币,每天还会长金币,输入会给出每棵树初始金币和每天会生长的金币,问你第M天最多可以得到多少金币,我的DP方程是二维的,而且最终题目要的答案就是 dp
[m],那DP方程的含义就不用多说了 ,状态转移方程就是
在进行DP之前要进行排序,以那个 每天生长的金币数从小到大来排,具体原因我不清楚,我就是假设n ==m的时候,那肯定是 按照每天生长的金币数来排序的,所以就YY了一下 没想到 1A
说说我的思想过程,拿第一个案例来说明,我们先把矩阵全部写成 0,因为构造类的案例输出是不唯一的,只要符合题目要求即可
00000
00000
00000.
00000
那么此时 矩阵正中央的6个0是符合题目要求的,所以此时的矩阵是6 nice矩阵,第一个案例要求是3nice,那么我们破坏三个
01230
00000
00000
00000
此时的矩阵就符合了,那么破坏掉的数目就是 (n-2)*(m-2) - k,那么我们会发现 只要每一行除却首尾从1到(n-2)*(m-2) - k填上去即可
不放心再检验第二个案例
01230
04560
00000
00000
看看 是不是(n-2)*(m-2)-k刚好等于6,在不放心再多写几个
在此打个小广告,都说咱们信息学院的不会享受生活不文雅,那么在此给一篇文章:让大家陶冶陶冶情操哈哈哈 http://www.sanwen.net/subject/3628849/
先来3206这道题目跟队友一起讨论WA了挺多把做出来的,题意是给你N个村庄,M条道路,道路是单向的,让你再建一条道路,使得这个图的连通分量最大,同时请输出最大连通分量 和 你所建的道路,
一开始完全想错,想到树链剖分,后来想暴力,看直接不行 就先进行强连通缩点,缩点完成后用DFS来进行查找,可惜超时,最后因为DFS发现有某些部分是重合查找,所有有些部分查找以后是可以递归返回值的,那么就是有递推的意思了,于是想到了树状DP,于是开始用树状DP, WA了有七把吧,给出代码
总体思路就是强连通缩点,然后进行树状DP
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<map> #include<vector> #include<stdlib.h> #define L(x) (x<<1) #define R(x) (x<<1|1) #define Mid(x,y) ((x+y)>>1) using namespace std; #define N 50010 //N为最大点数 #define M 501001 //M为最大边数 int n, m;//n m 为点数和边数 struct Edge{ int from, to, nex; }edge[M]; int head , edgenum; void add(int u, int v){//边的起点和终点 Edge E={u, v, head[u]}; edge[edgenum] = E; head[u] = edgenum++; } int DFN , Low , Stack , ttop, Time; //Low[u]是点集{u点及以u点为根的子树} 中(所有反向弧)能指向的(离根最近的祖先v) 的DFN[v]值(即v点时间戳) int taj;//连通分支标号,从1开始 int Belong ;//Belong[i] 表示i点属于的连通分支 bool Instack ; vector<int> bcc ; //标号从1开始 vector<int>G ; void tarjan(int u ,int fa){ DFN[u] = Low[u] = ++ Time ; Stack[ttop ++ ] = u ; Instack[u] = 1 ; for (int i = head[u] ; ~i ; i = edge[i].nex ){ int v = edge[i].to ; if(DFN[v] == -1) { tarjan(v , u) ; Low[u] = min(Low[u] ,Low[v]) ; } else if(Instack[v]) Low[u] = min(Low[u] ,DFN[v]) ; } if(Low[u] == DFN[u]){ int now; taj ++ ; bcc[taj].clear(); G[taj].clear(); do{ now = Stack[-- ttop] ; Instack[now] = 0 ; Belong [now] = taj ; bcc[taj].push_back(now); }while(now != u) ; } } void tarjan_init(int all){ for(int i = 0;i<=all;i++)DFN[i]=-1,Instack[i] = 0; ttop = Time = taj = 0; for(int i=1;i<=all;i++)if(DFN[i]==-1 )tarjan(i, i); //注意开始点标!!! } void suodian(){ for(int i = 0; i < edgenum; i++){ int u = Belong[edge[i].from], v = Belong[edge[i].to]; if(u!=v)G[u].push_back(v); } } ////////////////////////////////////// int uu, vv, ans; int siz ; int ch ; void dfs(int now, int TOP){ int v, TOP1=1000000; int now1 = bcc[now][0], TOPP = bcc[TOP][0]; for(int i = 0;i < G[now].size();i++){ v = G[now][i]; if(siz[v]==0)dfs(v,TOP); } int maxn = 0; for(int i =0;i<G[now].size();i++){ v = G[now][i]; if(maxn<siz[v])maxn = siz[v],TOP1=ch[v]; else if(maxn == siz[v]) TOP1=min(TOP1,ch[v]); } maxn += bcc[now].size(); if(G[now].size())ch[now] = TOP1; siz[now] = maxn; if(now==TOP) { now = bcc[now][0]; if(ans<maxn){ans = maxn;uu=TOP1;vv=now;} else if(ans==maxn){ if(uu>TOP1){uu=TOP1; vv=now;} else if(uu==TOP1)vv = min(vv,now); } } } void init(){ for(int i =1;i<=n;i++)head[i]=-1,siz[i] = 0; edgenum=0; } int main() { int t; int k, i,j; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); if(m==0){printf("1\n1 2\n");continue;} init(); while(m--){ int u,v; scanf("%d%d",&u,&v); add(u,v); } tarjan_init(n); if(taj==1){printf("%d\n1 2\n",n);continue;} suodian(); ans = 0; for(i=1;i<=taj;i++)ans = max(ans,(int)bcc[i].size()); uu = 1, vv= 2; for(i=1;i<=taj;i++)sort(bcc[i].begin(),bcc[i].end()); for(i=1;i<=taj;i++)if(G[i].size()==0)ch[i] = bcc[i][0], siz[i] = bcc[i].size(); for(i = 1;i<=taj;i++)if(siz[i]==0) { dfs(i,i); } printf("%d\n%d %d\n",ans,uu,vv); } return 0; } /* 99 2 1 1 2 2 0 2 2 1 2 2 1 5 4 1 3 2 3 3 4 3 5 8 9 1 2 2 3 3 1 3 4 4 5 5 6 6 4 6 7 8 7 6 6 1 2 2 3 3 1 4 5 5 6 6 4 8 7 1 2 2 3 3 1 4 5 5 6 6 7 7 8 */
接下来3211
这是一道DP的题目,
意思是 给你N棵树,M天时间,一天砍一棵树,如果你有一天不砍,那么以后就不能再砍了,树是摇钱树,所以一开始树上长了一些金币,每天还会长金币,输入会给出每棵树初始金币和每天会生长的金币,问你第M天最多可以得到多少金币,我的DP方程是二维的,而且最终题目要的答案就是 dp
[m],那DP方程的含义就不用多说了 ,状态转移方程就是
dp[i][j] = max(dp[i-1][j],dp[i-1][j-1] + node[i].a + node[i].b * (j - 1));
在进行DP之前要进行排序,以那个 每天生长的金币数从小到大来排,具体原因我不清楚,我就是假设n ==m的时候,那肯定是 按照每天生长的金币数来排序的,所以就YY了一下 没想到 1A
#include<iostream> #include<cstdio> #include<list> #include<algorithm> #include<cstring> #include<string> #include<queue> #include<stack> #include<map> #include<vector> #include<cmath> #include<memory.h> #include<set> #define ll long long #define eps 1e-8 #define inf 0xfffffff //const ll INF = 1ll<<61; using namespace std; typedef struct Node { int a,b; }; Node node[1000 + 5]; int dp[1000+ 5][1000 + 5]; void clear() { memset(node,0,sizeof(node)); memset(dp,0,sizeof(dp)); } bool cmp(Node x,Node y) { return x.b < y.b; } int main() { int t; scanf("%d",&t); while(t--) { int n,m; scanf("%d %d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&node[i].a); } for(int i=1;i<=n;i++) scanf("%d",&node[i].b); sort(node + 1,node + 1 + n,cmp); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { dp[i][j] = max(dp[i-1][j],dp[i-1][j-1] + node[i].a + node[i].b * (j - 1)); } } printf("%d\n",dp [m]); } return 0; }接下来是3212,题意 给你一个N*M的矩阵,如果矩阵中有一个元素等于它上下左右四个相邻元素的和 的话,那就有一个nice,让你求出一个 k nice的矩阵,因为以前浙大月赛遇到过一道构造类的题目,所以这道题很快花了8分钟就A了,
说说我的思想过程,拿第一个案例来说明,我们先把矩阵全部写成 0,因为构造类的案例输出是不唯一的,只要符合题目要求即可
00000
00000
00000.
00000
那么此时 矩阵正中央的6个0是符合题目要求的,所以此时的矩阵是6 nice矩阵,第一个案例要求是3nice,那么我们破坏三个
01230
00000
00000
00000
此时的矩阵就符合了,那么破坏掉的数目就是 (n-2)*(m-2) - k,那么我们会发现 只要每一行除却首尾从1到(n-2)*(m-2) - k填上去即可
不放心再检验第二个案例
01230
04560
00000
00000
看看 是不是(n-2)*(m-2)-k刚好等于6,在不放心再多写几个
#include<iostream> #include<cstdio> #include<list> #include<algorithm> #include<cstring> #include<string> #include<queue> #include<stack> #include<map> #include<vector> #include<cmath> #include<memory.h> #include<set> #define ll long long #define eps 1e-8 #define inf 0xfffffff //const ll INF = 1ll<<61; using namespace std; int main() { int t; int n,m,k; scanf("%d",&t); while(t--) { scanf("%d %d %d",&n,&m,&k); int tmp = (n - 2) * (m - 2) - k; for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { if(j == 0) printf("0 "); else if(j == m - 1) printf("0\n"); else { if(tmp == 0) printf("0 "); else printf("%d ",tmp--); } } } } return EXIT_SUCCESS; }
相关文章推荐
- zoj 3211 Dream City 贪心+动规
- ZOJ 3211 Dream City(DP)
- ZOJ-3211-Dream City-DP背包问题+贪心
- ZOJ-3211-Dream City【6th浙江省赛】【dp】
- ZOJ 3211 6th省赛 J Dream City【DP】
- zoj 3211 dream city 贪心 dp和记忆化搜索
- ZOJ 3211 Dream City【dp】
- ZOJ 3211 Dream City(DP)
- ZOJ 3211 Dream City(DP)
- ZOJ 3211 Dream City
- zoj 3211 Dream City
- ZOJ - 3211 Dream City
- zoj 3211 Dream City 动态规划
- ZOJ 3211 Dream City
- zoj 3211 - Dream City
- ZOJ 3211 Dream City(dp)
- zoj 3211 - Dream City
- ZOJ 3211 Dream City(线性DP)
- zoj 3211 Dream City(DP)
- ZOJ 3211 Dream City (J) DP