【BZOJ-1952】城市规划 [坑题] 仙人掌DP + 最大点权独立集(改)
1952: [Sdoi2010]城市规划
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 73 Solved: 23
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
2 2 3 4 1 2 3 10 11
1 2
2 3
1 3
3 5
5 4
5 6
4 7
6 7
8 9
Sample Output
【样例解释】
反和谐主义者选择的小区分别是小区3(看守的小区是小区1、小区2和小区5)、小区7(看守的小区是小区4和小区6)和小区9(看守的小区是小区8),这样会损失的总和谐值为3+3+11=17。
或者选择的小区分别是小区1(看守的小区是小区2和小区3)、小区4(看守的小区是小区5和小区7)和小区9(看守的小区是小区8),这样会损失的总和谐值为2+4+11=17。
如果同时选择小区3、小区4和小区9,虽然损失的总和谐值为18,但是小区3和小区4都要派猪来看守小区5,这不符合条件,故此方案不可行。
【数据约定】
对于20%的数据,保证每个点不存在于任何一个环中;
对于另外30%的数据,保证图中只存在一个环;
对于100%的数据,有N<=1000000,M<=2000000,所有的权值不超过1000。
HINT
Source
Solution
这是一道坑题,测试数据有误,标算有误,所以想要AC需要和标算错的一样 详见Discuss
询问了AC此题的Claris,得到的回复是:
说说正确做法:
仍旧是仙人掌DP,这里的话是仙人掌森林,不过原理是一样的e
求解最大点权独立集,然后仔细读样例发现,这里的“独立集”不同于平常的独立集,即不能选中间隔着一个的两个点
那么对于正常的求解方法是dp[i][0/1]表示当前到i位,选或不选的答案,这里就带限制的dp[i][0/1/2]去进行dp即可,转移是类似的
对仙人掌的处理方法一样是找环,拆环单独DP
Code
这里提供自己的正确做法(WA3组(数据有误)AC其余)
除discuss中提及的3组全A,并与提及的3组的正确答案相吻合
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; int read() {int x=0,f=1; char ch=getchar();while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}return x*f; } #define maxn 1000100 struct EdgeNode{int to,next;}edge[maxn<<2]; int head[maxn],cnt; void add(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;} void insert(int u,int v) {add(u,v); add(v,u);} int deep[maxn],fa[maxn],dfn[maxn],low[maxn],dp1[maxn][3],dp2[maxn][3],ring[maxn],HX[maxn],t; int n,m,ans;void CactusDP(int st,int tt) {ring[1]=tt; int zz=1;while (ring[zz]!=st) {ring[zz+1]=fa[ring[zz]]; zz++;}//printf("Num=%d :",zz);//for (int i=1; i<=zz; i++) printf("%d ->",ring[i]); printf("\n");int f0=0,f1=0,f2=0;for (int opt=0; opt<=2; opt++){dp2[1][0]=dp2[1][1]=dp2[1][2]=0;dp2[1][opt]=dp1[tt][opt];if (opt==2) dp2[1][1]=dp2[1][2];for (int i=2; i<=zz; i++)dp2[i][0]=dp2[i-1][2]+dp1[ring[i]][0],dp2[i][1]=max(max(dp2[i-1][1],dp2[i-1][0])+dp1[ring[i]][2],dp2[i-1][1]+dp1[ring[i]][1]),dp2[i][2]=max(dp2[i-1][1],dp2[i-1][2])+dp1[ring[i]][2];if (opt==0) f1=max(f1,dp2[zz][2]);if (opt==1) f1=max(f1,dp2[zz][1]),f2=max(f2,dp2[zz][2]);if (opt==2) f1=max(f1,dp2[zz][1]),f0=max(f0,dp2[zz][0]),f2=max(f2,dp2[zz][2]); }dp1[st][0]=f0; dp1[st][1]=f1; dp1[st][2]=f2; }void TreeDP(int now) {dfn[now]=low[now]=++t; dp1[now][2]=0; dp1[now][0]=HX[now]; int maxx=0;for (int i=head[now]; i; i=edge[i].next)if (edge[i].to!=fa[now]){if (deep[edge[i].to]) {low[now]=min(dfn[edge[i].to],low[now]); continue;}fa[edge[i].to]=now; deep[edge[i].to]=deep[now]+1;TreeDP(edge[i].to);if (low[edge[i].to]>low[now])dp1[now][2]+=max(dp1[edge[i].to][1],dp1[edge[i].to][2]),dp1[now][0]+=dp1[edge[i].to][2],maxx=max(maxx,dp1[edge[i].to][0]-max(dp1[edge[i].to][1],dp1[edge[i].to][2]));low[now]=min(low[now],low[edge[i].to]);}dp1[now][1]=maxx+dp1[now][2];for (int i=head[now]; i; i=edge[i].next)if (low[edge[i].to]==dfn[now] && edge[i].to!=fa[now] && deep[edge[i].to]!=deep[now]+1)CactusDP(now,edge[i].to); }void Freopen() {freopen("area.in","r",stdin); freopen("area.out","w",stdout);} void Fclose() {fclose(stdin); fclose(stdout);}int main() {//Freopen();n=read(),m=read();for (int i=1; i<=n; i++) HX[i]=read();for (int u,v,i=1; i<=m; i++) u=read(),v=read(),insert(u,v);for (int i=1; i<=n; i++) if (!dfn[i]) {fa[i]=i,deep[i]=1; TreeDP(i); ans+=max(dp1[i][0],max(dp1[i][1],dp1[i][2]));}printf("%d\n",ans);//Fclose();return 0; }
以及可A的标程,显然标程的判环是有些问题的
#include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; const int N = 1000500, inf = ~0U >> 1; #define forEdges(iter,u) for(edge* iter = e[u]; iter; iter = iter->n) struct edge { int t; edge *n; } ebf[N << 2], *e[N], *ec = ebf; int weight[N], n; int dfn[N], low[N], S[N], sTop, dTime; int f[N][3], rf[N][3], id[N], opt[N]; inline void updateN (int &x, int y) { if (x > y) x = y; } inline void updateX (int &x, int y) { if (x < y) x = y; } inline void dfs (int u, int au) { int v; dfn[u] = low[u] = ++dTime, S[++sTop] = u; forEdges(it, u) if ((v = it->t) != au) if (!dfn[v]) dfs(v, u), updateN(low[u], low[v]); else updateN(low[u], dfn[v]); int maxDelt(0); f[u][2] = 0, f[u][0] = weight[u]; forEdges(it, u) if ((v = it->t) != au && low[v] > dfn[u]) // Sons { f[u][2] += max(f[v][1], f[v][2]); f[u][0] += f[v][2]; updateX(maxDelt, f[v][0] - max(f[v][1], f[v][2])); } f[u][1] = f[u][2] + maxDelt; forEdges(it, u) if (low[it->t] == dfn[u]) // A ring { int rs = 0; while (S[sTop] != u) id[++rs] = S[sTop--]; id[++rs] = u; /* RingDP : Line 53 .. 55 */int f0 = 0, f1 = 0, f2 = 0; for (int st = 0; st <= 2; ++st) { rf[1][0] = rf[1][1] = rf[1][2] = 0; rf[1][st] = f[id[1]][st]; if (st == 2) rf[1][1] = rf[1][2]; for (int i = 2; i <= rs; ++i) { //RingDP rf[i][0] = f[id[i]][0] + rf[i - 1][2]; rf[i][1] = max(f[id[i]][2] + max(rf[i - 1][0], rf[i - 1][1]), f[id[i]][1] + rf[i - 1][1]); rf[i][2] = f[id[i]][2] + max(rf[i - 1][1], rf[i - 1][2]); } switch (st) { case 0 : updateX(f1, rf[rs][2]); break; //!! case 1 : updateX(f1, rf[rs][1]), updateX(f2, rf[rs][2]); break; case 2 : updateX(f0, rf[rs][0]), updateX(f1, rf[rs][1]), updateX(f2, rf[rs][2]); break; } } f[u][0] = f0, f[u][1] = f1, f[u][2] = f2; } if (dfn[u] == low[u]) while (S[sTop + 1] != u) --sTop; opt[u] = max(f[u][0], max(f[u][1], f[u][2])); } int main () { int m, a, b; // freopen("area.in", "r", stdin); // freopen("area.out", "w", stdout); scanf("%d%d", &n, &m); for (int i = 1; i <= n; ++i) scanf("%d", weight + i); while (m--) { scanf("%d%d", &a, &b); *ec = (edge){b, e[a]}; e[a] = ec++; *ec = (edge){a, e[b]}; e[b] = ec++; } int res = 0; for (int i = 1; i <= n; ++i) if (!dfn[i]) dfs(i, 0), res += opt[i]; //A Connected Component printf("%d\n", res); return 0; }
std
开荒做这种大坑,简直了= =||
转载于:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5596732.html
【BZOJ-1952】城市规划 [坑题] 仙人掌DP + 最大点权独立集(改)相关推荐
- hdu 3657 最大点权独立集变形(方格取数的变形最小割,对于最小割建图很好的题)...
转载:http://blog.csdn.net/cold__v__moon/article/details/7924269 /* 这道题和方格取数2相似,是在方格取数2的基础上的变形.方格取数2解法: ...
- POJ1466 最大点权独立集
题意: 给你n个人,再给你每个人都喜欢哪些人,让你找到一个最大的集合数,要求这个集合里面任意两个人都不喜欢彼此. 思路: 直接就是在问最大点权独立集元素个数,没啥解释的一遍二分 ...
- [网络流][最大点权独立集] 方格取数
预备知识: 点覆盖集:无向图G的一个点集,使得该图中所有边都至少有一个端点在该集合内. 最小点权覆盖集:在带点权无向图G中,点权之和最小的覆盖集. 点独立集:无向图G的一个点集,使得任两个在该集合中的 ...
- HDU 1569 最大点权独立集
最大点权独立集与最小点权覆盖是对偶问题,这里先介绍最小点权覆盖的解法. 最小点权覆盖问题是指,给出一张二分图,二分图的每个节点带有一个点权,要求从中选出若干节点,使得这些节点能够覆盖二分图中所有的 ...
- [最大点权独立集]AcWing 2326. 王者之剑
题目:AcWing 2326. 王者之剑 分析: 本题的三个性质: 只能在偶数时间取宝石 相邻格子不能同时取 将棋盘黑白染色组成二分图之后,独立集跟原题的合法方案一一对应 所以本题就是求一个二分图的最 ...
- [学习笔记]最小割之最小点权覆盖最大点权独立集
最小点权覆盖 给出一个二分图,每个点有一个非负点权 要求选出一些点构成一个覆盖,问点权最小是多少 建模: S到左部点,容量为点权 右部点到T,容量为点权 左部点到右部点的边,容量inf 求最小割即可. ...
- POJ3692 最大点权独立集元素个数
题意: n个男孩和m个女孩,给你他们谁和谁彼此了解,问你要找到一个集合,使得这个集合中的男孩和女孩相互了解,并且人数最多. 思路: 简单题目,其实就是在求最大点权独立集元素个数,先 ...
- hdu 1569 方格取数(2) 最大点权独立集
二分图. 最大点权独立集=总权-最小点权覆盖集. 哪位大神能给一些二分图 最大点权独立集等等 的相关资料!!!!!跪谢 用网络流求解最小点权覆盖集即可,建图不讲了. #include<cstdi ...
- [luoguP2774] 方格取数问题(最大点权独立集)
传送门 引入两个概念: 最小点权覆盖集:满足每一条边的两个端点至少选一个的最小权点集. 最大点权独立集:满足每一条边的两个端点最多选一个的最大权点集. 现在对网格染色,使得相邻两点颜色不同,之后把两个 ...
最新文章
- MySql 密码忘记了,不用重装
- Bootstrap响应式与自适应区别
- [zz]用U盘装win7/XP系统的操作[图解]
- 修改场景默认pawn的方法
- oracle sql 查询优化器,基于ORACLE成本优化器的SQL查询优化分析与应用
- oracle 二进制与运算,Oracle怎么操作进行二进制的比对
- autofac获取全局Container
- 《深入理解Java虚拟机:JVM高级特性与最佳实践》 (第3版)周志明 著
- Xutils-Android中数据存储和网络传输的框架
- html5 小车动画_html5 echarts汽车仪表盘图表动画特效
- 洛谷 P2672 推销员 解题报告
- 左偏树(XJT Love Trees,玲珑杯 Round#8 C lonlife 1081)
- python爬斗鱼直播房间名和主播名_python3爬取斗鱼某些版块的主播人气
- 开源生态|打造活力开源社区,共建开源新生态!
- Python 安装PyQt5失败:Permission denied:d3dcompiler_47.dll
- FM33LC02X FreeRTOS MDK 移植记录总结
- matlab绘图去白边
- opengles的双PBO
- 图形开发——显卡学习
- 复现上篇文章故障得知:网卡错误56,Windows 仍在设置此设备的类配置的原因