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. iOS多线程开发

    概览 大家都知道,在开发过程中应该尽可能减少用户等待时间,让程序尽可能快的完成运算.可是无论是哪种语言开发的程序最终往往转换成汇编语言进而解释成机器码来执行.但是机器码是按顺序执行的,一个复杂的多步操 ...

  2. MySQL 的乐观并发控制Optimistic concurrency control

    默认情况下, MySQL的Innodb事务隔离级别是重复读 repeatable read, SELECT @@GLOBAL.tx_isolation, @@tx_isolation;REPEATAB ...

  3. WPF DatePicker默认显示当前日期

    WPF的日历选择控件默认为当前日期,共有两种方法,一种静态,一种动态. 静态的当然写在DatePicker控件的属性里了,动态的写在对应的cs文件里,具体请看下面.     1.方法一:     my ...

  4. Python之线程、进程和协程

    python之线程.进程和协程 目录: 引言 一.线程 1.1 普通的多线程 1.2 自定义线程类 1.3 线程锁 1.3.1 未使用锁 1.3.2 普通锁Lock和RLock 1.3.3 信号量(S ...

  5. Gruntjs: grunt-usemin使用心得

    grunt-usemin: Replaces references to non-optimized scripts or stylesheets into a set of HTML files u ...

  6. 读书摘要,Hackable Projects

    完整读完Google的三篇谈Hackable Projects的文章,以及一篇从Test Pyramid看UnitTest的比重.一篇谈Optimal Logging的文章,感觉这5篇在测试.日志两个 ...

  7. K-means算法及文本聚类实践

    K-Means是常用的聚类算法,与其他聚类算法相比,其时间复杂度低,聚类的效果也还不错,这里简单介绍一下k-means算法,下图是一个手写体数据集聚类的结果. 基本思想 k-means算法需要事先指定 ...

  8. 2014 todo list

    1. 做好已知的各种项目,争取能成立固定团队2. 横向扩展技术学习,了解各种技术,加强技术素养3. 争取找个妹子4. 加强音律学习5. 继续发展各业余爱好6. 努力摇号 年底看收成.

  9. sqlserver查询所有表名、字段名、类型、长度和存储过程、视图的创建语句

    -- 获得存储过程创建语句 select o.xtype,o.name,cm.text from syscomments cm inner join sysobjects o on o.id=cm.i ...

  10. 如何解决Windows 10系统下设备的声音问题

    如何解决Windows 10系统下设备的声音问题? 请阅读下面的说明来解决Windows 10设备上的声音问题. 1. 检查设备管理器 打开开始菜单,键入设备管理器, 从出现的结果中选择并打开它. 在 ...