1952: [Sdoi2010]城市规划

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit:
73  Solved: 23
[Submit][Status][Discuss]

Description

小猪iPig来到了一个叫做pigsty的城市里,pigsty是一座专门为小猪所准备的城市,城市里面一共有n个小区给小猪们居住,并且存在许多条无向边连接着许多小区。因为这里是一个和谐的城市,所以小猪iPig准备在这个城市里面度过他的余生。若干年之后小猪iPig当上了规划局长,这件事令他非常开心。不过与此同时pigsty城市里面出现了许多反和谐主义者,他们已经厌烦了这样和谐的生活,在城市里到处闹事。小猪iPig为了更好地控制局面,他把城市改造成了另外一个样子:iPig把道路全部摧毁之后重新修建了m条无向边,并且保证每一个小区最多存在于一个由无向边组成的环中。
iPig以为这样做就让那些反和谐主义者不敢继续猖狂下去了,谁知到在新的城市道路修建好以后反和谐主义者宣言要对城市的小区进行一次洗脑!这下可麻烦了,iPig赶紧收集了许多的情报。iPig给每个小区标记了一个和谐值HX_i,用它来表示第i个小区的和谐程度。通过地下消息iPig又得知那些反和谐主义者进攻时有个规律:他们会选择若干个小区下手,这些小区都派一只猪过去,把这些小区的和谐值归零。在这个过程中,每个选择的小区所直接连接着的几个小区都派了一只猪去看守——以防被警猪给干扰。这个计划看似完美但是还是存在一个漏洞:因为人员之间都是在网络上认识的,互相没有见过面,为了防止不必要的麻烦(认错猪之类),每个小区最多只会有一头猪存在。
iPig突然感到了莫大的压力,他想知道在最坏情况下会丢失多少和谐值。但是不懂计算机的他不知道应该怎样计算。你能帮帮他吗?

Input

输入第一行有两个整数n和m,表示pigsty城市里面有n个小区,在iPig修整城市后有m条无向边连接着n个小区。接下来一行有n个正整数,第i个正整数HX_i表示第i个小区的和谐值为HX_i。接下来m行,每行两个正整数a和b(1<=a,b<=n),表示存在一条连接着小区a和小区
b的无向边。

Output

输出只有一行一个整数,表示最坏情况下损失的和谐值为多少。

Sample Input

9 9
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

17

【样例解释】
反和谐主义者选择的小区分别是小区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=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
#define maxn 1000100
struct EdgeNode{int to,next;}edge[maxn<<];
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][],dp2[maxn][],ring[maxn],HX[maxn],t;
int n,m,ans; void CactusDP(int st,int tt)
{
ring[]=tt; int zz=;
while (ring[zz]!=st) {ring[zz+]=fa[ring[zz]]; zz++;}
//printf("Num=%d :",zz);
//for (int i=1; i<=zz; i++) printf("%d ->",ring[i]); printf("\n");
int f0=,f1=,f2=;
for (int opt=; opt<=; opt++)
{
dp2[][]=dp2[][]=dp2[][]=;
dp2[][opt]=dp1[tt][opt];
if (opt==) dp2[][]=dp2[][];
for (int i=; i<=zz; i++)
dp2[i][]=dp2[i-][]+dp1[ring[i]][],
dp2[i][]=max(max(dp2[i-][],dp2[i-][])+dp1[ring[i]][],dp2[i-][]+dp1[ring[i]][]),
dp2[i][]=max(dp2[i-][],dp2[i-][])+dp1[ring[i]][];
if (opt==) f1=max(f1,dp2[zz][]);
if (opt==) f1=max(f1,dp2[zz][]),f2=max(f2,dp2[zz][]);
if (opt==) f1=max(f1,dp2[zz][]),f0=max(f0,dp2[zz][]),f2=max(f2,dp2[zz][]);
}
dp1[st][]=f0; dp1[st][]=f1; dp1[st][]=f2;
} void TreeDP(int now)
{
dfn[now]=low[now]=++t;
dp1[now][]=; dp1[now][]=HX[now]; int maxx=;
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]+;
TreeDP(edge[i].to);
if (low[edge[i].to]>low[now])
dp1[now][]+=max(dp1[edge[i].to][],dp1[edge[i].to][]),
dp1[now][]+=dp1[edge[i].to][],
maxx=max(maxx,dp1[edge[i].to][]-max(dp1[edge[i].to][],dp1[edge[i].to][]));
low[now]=min(low[now],low[edge[i].to]);
}
dp1[now][]=maxx+dp1[now][];
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]+)
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=; i<=n; i++) HX[i]=read();
for (int u,v,i=; i<=m; i++) u=read(),v=read(),insert(u,v);
for (int i=; i<=n; i++) if (!dfn[i]) {fa[i]=i,deep[i]=; TreeDP(i); ans+=max(dp1[i][],max(dp1[i][],dp1[i][]));}
printf("%d\n",ans);
//Fclose();
return ;
}

以及可A的标程,显然标程的判环是有些问题的

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std; const int N = , inf = ~0U >> ; #define forEdges(iter,u) for(edge* iter = e[u]; iter; iter = iter->n)
struct edge { int t; edge *n; }
ebf[N << ], *e[N], *ec = ebf; int weight[N], n;
int dfn[N], low[N], S[N], sTop, dTime;
int f[N][], rf[N][], 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();
f[u][] = , f[u][] = weight[u];
forEdges(it, u) if ((v = it->t) != au && low[v] > dfn[u]) // Sons
{
f[u][] += max(f[v][], f[v][]);
f[u][] += f[v][];
updateX(maxDelt, f[v][] - max(f[v][], f[v][]));
}
f[u][] = f[u][] + maxDelt; forEdges(it, u) if (low[it->t] == dfn[u]) // A ring
{
int rs = ;
while (S[sTop] != u) id[++rs] = S[sTop--];
id[++rs] = u;
/* RingDP : Line 53 .. 55 */
int f0 = , f1 = , f2 = ;
for (int st = ; st <= ; ++st)
{
rf[][] = rf[][] = rf[][] = ;
rf[][st] = f[id[]][st];
if (st == ) rf[][] = rf[][];
for (int i = ; i <= rs; ++i)
{ //RingDP
rf[i][] = f[id[i]][] + rf[i - ][];
rf[i][] = max(f[id[i]][] + max(rf[i - ][], rf[i - ][]), f[id[i]][] + rf[i - ][]);
rf[i][] = f[id[i]][] + max(rf[i - ][], rf[i - ][]);
}
switch (st)
{
case : updateX(f1, rf[rs][]); break; //!!
case : updateX(f1, rf[rs][]), updateX(f2, rf[rs][]); break;
case : updateX(f0, rf[rs][]), updateX(f1, rf[rs][]), updateX(f2, rf[rs][]); break;
}
}
f[u][] = f0, f[u][] = f1, f[u][] = f2;
} if (dfn[u] == low[u]) while (S[sTop + ] != u) --sTop;
opt[u] = max(f[u][], max(f[u][], f[u][]));
} int main ()
{
int m, a, b;
// freopen("area.in", "r", stdin);
// freopen("area.out", "w", stdout);
scanf("%d%d", &n, &m);
for (int i = ; 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 = ;
for (int i = ; i <= n; ++i)
if (!dfn[i]) dfs(i, ), res += opt[i]; //A Connected Component
printf("%d\n", res);
return ;
}

std

开荒做这种大坑,简直了= =||

【BZOJ-1952】城市规划 [坑题] 仙人掌DP + 最大点权独立集(改)的更多相关文章

  1. BZOJ 1475 方格取数(二分图最大点权独立集)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1475 [题目大意] 给出一个n*n的方格,从中取一些不相邻的数字,使得和最大 [题解] ...

  2. HDU 1565 1569 方格取数(最大点权独立集)

    HDU 1565 1569 方格取数(最大点权独立集) 题目链接 题意:中文题 思路:最大点权独立集 = 总权值 - 最小割 = 总权值 - 最大流 那么原图周围不能连边,那么就能够分成黑白棋盘.源点 ...

  3. LibreOJ #6007. 「网络流 24 题」方格取数 最小割 最大点权独立集 最大流

    #6007. 「网络流 24 题」方格取数 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据   题目描述 ...

  4. hdu 3657 最大点权独立集变形(方格取数的变形最小割,对于最小割建图很好的题)

    转载:http://blog.csdn.net/cold__v__moon/article/details/7924269 /* 这道题和方格取数2相似,是在方格取数2的基础上的变形. 方格取数2解法 ...

  5. HDU 1569 - 方格取数(2) - [最大点权独立集与最小点权覆盖集]

    嗯,这是关于最大点权独立集与最小点权覆盖集的姿势,很简单对吧,然后开始看题. 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1569 Time Limi ...

  6. hdu1569 方格取数(2) 最大点权独立集=总权和-最小点权覆盖集 (最小点权覆盖集=最小割=最大流)

    /** 转自:http://blog.csdn.net/u011498819/article/details/20772147 题目:hdu1569 方格取数(2) 链接:https://vjudge ...

  7. hdu1569 方格取数 求最大点权独立集

    题意:一个方格n*m,取出一些点,要求两两不相邻,求最大和.思路:建图,相邻的点有一条边,则建立了一个二分图,求最大点权独立集(所取点两两无公共边,权值和最大),问题转化为求总权和-最小点权覆盖集(点 ...

  8. POJ1466 最大点权独立集

    题意:       给你n个人,再给你每个人都喜欢哪些人,让你找到一个最大的集合数,要求这个集合里面任意两个人都不喜欢彼此. 思路:       直接就是在问最大点权独立集元素个数,没啥解释的一遍二分 ...

  9. HDU 1565 最大点权独立集

    首先要明白图论的几个定义: 点覆盖.最小点覆盖: 点覆盖集即一个点集,使得所有边至少有一个端点在集合里.或者说是“点” 覆盖了所有“边”.. 最小点覆盖(minimum vertex covering ...

随机推荐

  1. html代码中显示系统时间

    可以显示系统的静态时间和动态时间 1,静态时间 <script type="text/javascript"> var myDate = new Date(); doc ...

  2. 使用gogs,drone搭建自动部署

    使用gogs,drone搭建自动部署 使用gogs,drone,docker搭建自动部署测试环境 Gogs是一个使用go语言开发的自助git服务,支持所有平台Docker是使用go开发的开源容器引擎D ...

  3. python强大的区间处理库interval用法介绍

    原文发表在我的博客主页,转载请注明出处 前言 这个库是在阅读别人的源码的时候看到的,觉得十分好用,然而在网上找到的相关资料甚少,所以阅读了源码来做一个简单的用法总结.在网络的路由表中,经常会通过掩码来 ...

  4. Tensorflow学习笔记3:TensorBoard可视化学习

    TensorBoard简介 Tensorflow发布包中提供了TensorBoard,用于展示Tensorflow任务在计算过程中的Graph.定量指标图以及附加数据.大致的效果如下所示, Tenso ...

  5. ASP.NET 页面缓存

    ASP.NET 实现页面缓存页面缓存的使用方法非常的简单,只需要在aspx页的顶部加一句声明<%@ OutputCache Duration="60" VaryByParam ...

  6. 【转】赶集网mysql开发36军规

    原文链接:https://segmentfault.com/a/1190000004711147 写在前面的话:总是在灾难发生后,才想起容灾的重要性:总是在吃过亏后,才记得曾经有人提醒过. (一)核心 ...

  7. hdu1754 I hate it线段树模板 区间最值查询

    题目链接:这道题是线段树,树状数组最基础的问题 两种分类方式:按照更新对象和查询对象 单点更新,区间查询; 区间更新,单点查询; 按照整体维护的对象: 维护前缀和; 维护区间最值. 线段树模板代码 # ...

  8. 屠龙之路_坚持就是胜利_NinthDay

    狭小的空间里,屠龙天团的少年们和alpha恶龙苦苦对峙了一夜!这恶龙还挺能熬的,厉害了word龙.无奈之下,五更天的时候,我们的屠龙少年只能先退出战场养精蓄锐,为了不让恶龙再次逍遥法外,机智的屠龙队长 ...

  9. Java--笔记(1)

    1.Swing 是在AWT的基础上构建的一套新的图形界面系统,它提供了AWT 所能够提供的所有功能,并且用纯粹的Java代码对AWT 的功能进行了大幅度的扩充.AWT 是基于本地方法的C/C++程序, ...

  10. QMenu,contextmenuevent,窗体透明

    void MainWindow::contextMenuEvent(QContextMenuEvent *event) { QMenu *menu=newQMenu; menu->addActi ...