拆点问题

题目详情

n个节点,m条边的无向图,每个节点一个权值w。定义拆除一个节点的代价为与其相邻的节点的权值之和。拆除一个节点后删除所有与该节点相连的边。求拆除所有节点需要花费的最少代价。输入描述:输入包含多组测试数据,每组测试数据第一行先输入n,m(1 ≤ n ≤ 10000; 0 ≤ m ≤ 20000),第二行输入n个整数wi(0 ≤ wi ≤ 105),接下来的m行,每行两个整数u,v代表节点u与v相连(1 ≤ ui, vi ≤ n; ui ≠ vi).输出描述:对于每组测试数据,输出拆除所有节点需要花费的最少代价。

答题说明

样例输入:

4 3

10 20 30 40

1 4

1 2

2 3

样例输出:

40

Note:

其中一种拆除策略是:

先拆除节点3,代价为20

再拆除节点2,代价为10

再拆除节点4,代价为10

最后拆除节点1,代价为0

所以总的代价=20+10+10+0=40

解析:我以为这道题要用贪心算法:每次都删掉最小权值的点.所以我就写了这么多.答案是错误.

而实际上,没必要,每条边都要删掉的!只要把边的一端删掉就可以删掉此边了.

所以,把所有的边的权值加起来就行了.

因为所有点到最后都需要拆,则拆点的过程会涉及每一条边。因此我们对每一条边,取该边的两个顶点中权值较小的作为拆除该边的代价,最终统计拆除所有边所需要的最小代价和,即为所求解。

经验一:不要高估二星题.想的复杂了,必然不对.

经验二:换个角度看问题,别有洞天.

经验三:对过程寻求另一种描述.当我们把注意力放在点上的时候,谁能想到突破口在边上.

#include<stdio.h>
#include<string.h>
int a[10000];
int c[10000];
char b[10000][10000];
void main(){
    int n, m;
    int i,j, x,y;
    int min;
    int ans = 0;
    int size;
    //freopen("in.txt", "r", stdin);
    memset(b, 0, sizeof(b));
    memset(c, 0, sizeof(c));
    scanf("%d%d", &n, &m);
    size = n;
    for (i = 0; i < n; i++)
        scanf("%d", &a[i]);
    for (i = 0; i < m; i++)
    {
        scanf("%d%d", &x, &y);
        x--; y--;
        b[x][y]=b[y][x] = 1;
        c[x] += a[y];
        c[y] += a[x];
    }
    min = 0;
    for (i = 1; i < n;i++)
    if (c[i] <= c[min]&&a[i]>a[min])min = i;
again:ans += c[min];
    j = min;
    c[j] = -1;
    for (i = 0; c[i] < 0; i++);
    min = i;
    for (; i < n; i++)
    {
        if (b[j][i] == 1&&c[i]>=0)c[i] -= a[j];
        if (c[i] <= c[min]&&c[i]>=0&&a[i]>a[min])min = i;
    }
    size--;
    if(size>0)goto again;
    printf("%d", ans);
}        

时间: 2024-08-22 19:11:21

拆点问题的相关文章

深入剖析Java中的装箱和拆箱

阅读目录 一.什么是装箱?什么是拆箱?二.装箱和拆箱是如何实现的三.面试中相关的问题 自动装箱和拆箱问题是Java中一个老生常谈的问题了,今天我们就来一些看一下装箱和拆箱中的若干问题.本文先讲述装箱和拆箱最基本的东西,再来看一下面试笔试中经常遇到的与装箱.拆箱相关的问题. 回到顶部 一.什么是装箱?什么是拆箱? 我们知道 Java为每种基本数据类型都提供了对应的包装器类型,至于为什么会为每种基本数据类型提供包装器类型在此不进行阐述,有兴趣的朋友可以查阅相关资料.在Java SE5之前,如果要生成

hdu4725 拆点+最短路

题意:有 n 个点,每个点有它所在的层数,最多有 n 层,相邻两层之间的点可以互相到达,消耗 c (但同一层并不能直接到达),然后还有一些额外的路径,可以在两点间互相到达,并且消耗一定费用.问 1 点到 n 点的最小花费 将每一层拆成两个点,分别为进入层和出发层,然后相邻层的出发层可以指向进入层,花费 c,每个点可以到达其出发层,而进入层可以到达该点,花费 0 ,最后建立其余双向边,最短路 1 #include<stdio.h> 2 #include<string.h> 3 #in

hdoj 4289 Control 【拆点 求最小割】

Control Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2295    Accepted Submission(s): 961 Problem Description You, the head of Department of Security, recently received a top-secret informati

HDU 3998 Sequence (最长递增子序列+最大流SAP,拆点法)经典

Sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1666    Accepted Submission(s): 614 Problem Description There is a sequence X (i.e. x[1], x[2], ..., x[n]). We define increasing subsequ

分拆数组技巧应用

给你一个数组A[1..n],请你在O(n)的时间里构造一个新的数组B[1..n],使得B[i]=A[1]*A[2]*...*A[n]/A[i].你不能使用除法运算. 思路1:题目中说明,不能用除法,那一定是在相乘的时候,省略那一项,然后时间复杂度要0(n),就不能两层循环,而是要利用前面的相乘信息来降低复杂度. 算法:相似的分拆技术在数组题中.线性时间构造两个新数组,从开始遍历相乘 T1[0] =1,T1[i]=T[i-1]*A[i-1]  ;而 T2从后往前遍历相乘 T2[len-1] =1,

poj3436--ACM Computer Factory(最大流,拆点dinic)

ACM Computer Factory Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5501   Accepted: 1887   Special Judge Description As you know, all the computers used for ACM contests must be identical, so the participants compete on equal terms. Th

自动装箱/自动拆箱/注释之反编译示例

下面是源码: 1 package test; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 public class Test { 7 public static void main(String[] args) { 8 List<Integer> list = new ArrayList<>(); 9 //下面会触发编译器自动装箱 10 list.add(1); 11 //下面会触发编译器自动拆箱 12

装箱与拆箱

一.装箱机制: 1,在托管堆中分配内存.分配的内存量是值类型各字段所需的内存量,还要加上托管堆中所有对象都有的两个额外成员(类型对象指针和同步块索引)所需的内存量2,值类型字段复制到新分配的堆内存3,返回对象地址.现在该地址是对象的引用:值类型成了引用类型 二.拆箱机制 1,获取已装箱值类型对象中的各个字段的地址(这个过程是装箱)2,将字段包含的值从堆复制到基于栈的值类型字段实例中3,如果包含"对已装箱值类型实例的引用"的变量为null,抛出NullReferenceException

华硕A450c详细清灰拆机教程

很久都想写点东西,但又无从下笔. 上次把自己的笔记本清了灰,这次有时间就整理一下,随便作为我的第一次随笔. 准备:笔记本(我的是华硕A450c),拆机工具(螺丝刀等) 温馨提示:要慢点 1,先翻开笔记本背面,去锁卸下电池. 2,卸下对应螺丝,取下硬盘翻盖,右边的那一块就是硬盘,螺丝最好分开放. 3,接下来就把取硬盘,往右一推就出来了. 4,背面工作就完了,现在看看前面,用翘板沿着边缘慢慢翘,这里危机四伏,我牺牲了两三个暗扣... 5,键盘敲松后,试着拆开,记住此时要慢慢的,图中的位置有三个排线,

【GDKOI2016Day1T1-魔卡少女】【拆位】线段树维护区间内所有连续子区间的异或和

题意:给出N个数,M个操作.操作有修改和询问两种,每次修改将一个数改成另一个数,每次询问一个区间的所有连续子区间的异或和.n,m<=100000,ai<=1000 题解: 当年(其实也就是今年)做不出来的题..D1T1啊... 因为ai<=1000,我们可以拆位处理.拆成10个二进制位,每位开1棵线段树. 对于每个节点,维护: d:这段区间的异或和 L[0],L[1]:子区间一定从左端点开始,异或和为0,1的子区间分别有多少个 R[0],R[1]:子区间一定从右端点开始,异或和为0,1的