HDU 4005 The war Tarjan+dp

The war

Problem Description

In the war, the intelligence about the enemy is very important. Now, our troop has mastered the situation of the enemy‘s war zones, and known that these war zones can communicate to each other directly or indirectly through the network. We also know the enemy is going to build a new communication line to strengthen their communication network. Our task is to destroy their communication network, so that some of their war zones can‘t communicate. Each line has its "cost of destroy". If we want to destroy a line, we must spend the "cost of destroy" of this line. We want to finish this task using the least cost, but our enemy is very clever. Now, we know the network they have already built, but we know nothing about the new line which our enemy is going to build. In this condition, your task is to find the minimum cost that no matter where our enemy builds the new line, you can destroy it using the fixed money. Please give the minimum cost. For efficiency, we can only destroy one communication line.

Input

The input contains several cases. For each cases, the first line contains two positive integers n, m (1<=n<=10000, 0<=m<=100000) standing for the number of the enemy‘s war zones (numbered from 1 to n), and the number of lines that our enemy has already build. Then m lines follow. For each line there are three positive integer a, b, c (1<=a, b<=n, 1<=c<=100000), meaning between war zone A and war zone B there is a communication line with the "cost of destroy " c.

Output

For each case, if the task can be finished output the minimum cost, or output ‐1.

Sample Input

3 2
1 2 1
2 3 2
4 3
1 2 1
1 3 2
1 4 3

Sample Output

-1
3

Hint

For the second sample input: our enemy may build line 2 to 3, 2 to 4,

3 to 4. If they build line 2 to 3, we will destroy line 1 to 4, cost 3. If they

build line 2 to 4, we will destroy line 1 to 3, cost 2. If they build line 3 to 4,

we will destroy line 1 to 2, cost 1. So, if we want to make sure that we can

destroy successfully, the minimum cost is 3.

题意:

  给你一个n点m边的无向图

  有边权

  现在你可以选任意两个没有边相连的点连一条边,求新图的割边最小边的最大值

题解:

  考虑缩环之后就是一个树

  加一条边形成环,那么这个原树的最小边必然要在这个环内才能使得答案更加优

  找到这条边的两个端点,dfs这两个点,尽量走含有边权最小的链,这个dp处理即可

  dp[u][0/1]分别表示从u这个点开始走一条链含有的最小值和次小值

  最后就是两个端点走出的链的次小值取最小就是答案

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define ls i<<1
#define rs ls | 1
#define pii pair<int,int>
#define MP make_pair
typedef long long LL;
const long long INF = 1e18;
const double Pi = acos(-1.0);
const int N = 1e4+10, M = 1e5, mod = 1e9+7, inf = 2e9;

int ans,scc,t,top,tot,head[N],n,m,dp[N][2],a[N],b[N],c[N];
struct edge{int id,to,next,value;}e[M];

void add(int u,int v,int w) {e[t].next = head[u];e[t].to=v;e[t].value=w;e[t].id=0;head[u]=t++;}

int dfn[N],q[N],inq[N],low[N],belong[N],hav[N];

vector<pair<int ,int > > G[N];
void init() {
        for(int i = 0; i <= n; ++i) dp[i][0] = dp[i][1] = inf;
        for(int i = 1; i <= n; ++i) G[i].clear();
        memset(hav,0,sizeof(hav));
        memset(dfn,0,sizeof(dfn));
        memset(head,-1,sizeof(head));
        t = tot = top = scc = 0;
}
void dfs(int u) {
        low[u] = dfn[u] = ++tot;
        q[++top] = u; inq[u] = 1;
        for(int i = head[u]; i!=-1; i = e[i].next) {
            int to = e[i].to;
            if(e[i].id) continue;
            e[i].id = e[i ^ 1].id = 1;
            if(!dfn[to]) {
                dfs(to);
                low[u] = min(low[u],low[to]);
            } else if(inq[to]) low[u] = min(low[u],dfn[to]);
        }
        if(low[u] == dfn[u]) {
            scc++;
            do{
                inq[q[top]] = 0;
                belong[q[top]] = scc;
            }while(u != q[top--]);
        }
}
void dfs_ans(int u,int fa) {
        if(u == -1) return ;
        int fi = 0;
        for(int i = 0; i < G[u].size(); ++i) {
            int to = G[u][i].first;
            int value = G[u][i].second;
            if(to == fa) continue;
            dfs_ans(to,u);
           if(!fi) {
                dp[u][0] = min(value,dp[to][0]);
                dp[u][1] = dp[to][1];
                fi = 1;
            } else {
                if(min(value,dp[to][0]) < dp[u][0])  dp[u][1] = min(dp[u][0],min(dp[to][1],dp[u][1])),dp[u][0] = min(value,dp[to][0]);
                else dp[u][1] = min(dp[u][1],min(value,dp[to][0]));
            }
        }
}
void Tarjan() {
        int mi = inf, s = -1, t = -1;
        for(int i = 1; i <= n; ++i) if(!dfn[i]) dfs(i);
        for(int i = 1; i <= m; ++i) {
            int fx = belong[a[i]];
            int fy = belong[b[i]];
            if(fx != fy) {
                G[fx].push_back(MP(fy,c[i]));
                G[fy].push_back(MP(fx,c[i]));
               // cout<<fx<<" "<<fy<<endl;
                if(c[i] < mi) {
                    s = fx,t = fy;
                    mi = c[i];
                }
            }
        }
        ans = inf;
        dfs_ans(s,t);
        dfs_ans(t,s);
        if(s != -1 && t != -1)ans = min(dp[s][1],dp[t][1]);
        if(ans == inf) printf("%d\n",-1);
        else printf("%d\n",ans);
}
int main() {
        while(~scanf("%d%d",&n,&m)) {
            init();
            for(int i = 1; i <= m; ++i) {
                scanf("%d%d%d",&a[i],&b[i],&c[i]);
                add(a[i],b[i],c[i]);add(b[i],a[i],c[i]);
            }
            Tarjan();
        }
    return 0;
}
时间: 2024-10-13 16:06:07

HDU 4005 The war Tarjan+dp的相关文章

HDU 4005 The war(双连通好题)

HDU 4005 The war 题目链接 题意:给一个连通的无向图,每条边有一个炸掉的代价,现在要建一条边(你不不知道的),然后你要求一个你需要的最少代价,保证不管他建在哪,你都能炸掉使得图不连通 思路:炸肯定要炸桥,所以先双连通缩点,得到一棵树,树边是要炸的,那么找一个最小值的边,从该边的两点出发,走的路径中,把两条包含最小值的路径,的两点连边,形成一个环,这个环就保证了最低代价在里面,除了这个环以外的最小边,就是答案,这样的话,就利用一个dfs,搜到每个子树的时候进行一个维护即可 代码:

hdu 4005 The war

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4005 In the war, the intelligence about the enemy is very important. Now, our troop has mastered the situation of the enemy's war zones, and known that these war zones can communicate to each other direc

hdu 3555 Bomb(数位dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555 题目大意:就是给你一个数n,判断从0到n有多少个数含有数字49...... 是不是觉得跟hdu2089很相似呀... 思路:跟hdu2089一样的,注意给出的数比较大,所以这儿用__int64  .... code: #include<cstdio> #include<iostream> #include<cstring> #include<algorithm&

HDU 1231 最大连续子序列 DP题解

典型的DP题目,增加一个额外要求,输出子序列的开始和结尾的数值. 增加一个记录方法,nothing special. 记录最终ans的时候,同时记录开始和结尾下标: 更新当前最大值sum的时候,更新开始节点. const int MAX_N = 10001; long long arr[MAX_N]; int N, sta, end; long long getMaxSubs() { long long sum = 0, ans = LLONG_MIN; int ts = 0; for (int

[ACM] hdu 2089 不要62(数位Dp)

不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 19043    Accepted Submission(s): 6442 Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer). 杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就

HDU 4901 The Romantic Hero(DP)

HDU 4901 The Romantic Hero 题目链接 题意:给定一个序列,要求找一个分界点,然后左边选一些数异或和,和右边选一些数且和相等,问有几种方法 思路:dp,从左往右和从右往左dp,求出异或和且的个数,然后找一个分界点,使得一边必须在分界点上,一边随意,然后根据乘法原理和加法原理计算 代码: #include <cstdio> #include <cstring> typedef __int64 ll; const int N = 1024; const int

HDU 1160 FatMouse&#39;s Speed DP题解

本题就先排序老鼠的重量,然后查找老鼠的速度的最长递增子序列,不过因为需要按原来的标号输出,故此需要使用struct把三个信息打包起来. 查找最长递增子序列使用动态规划法,基本的一维动态规划法了. 记录路径:只需要记录后继标号,就可以逐个输出了. #include <stdio.h> #include <algorithm> using namespace std; const int MAX_N = 1005; struct MouseSpeed { int id, w, s; b

HDU 2089 不要62(数位DP,三种姿势)

HDU 2089 不要62(数位DP,三种姿势) ACM 题目地址:HDU 2089 题意: 中文题意,不解释. 分析: 100w的数据,暴力打表能过 先初始化dp数组,表示前i位的三种情况,再进行推算 直接dfs,一遍搜一变记录,可能有不饥渴的全部算和饥渴的部分算情况,记录只能记录全部算(推荐看∑大的详细题解Orz) 代码: 1. 暴力 (以前写的) /* * Author: illuz <iilluzen[at]gmail.com> * File: 2089_bf.cpp * Create

HDU 2084 数塔 --- 入门DP

HDU 2084 数塔 从下往上递推,状态转移方程 dp[i][j] = max( dp[i+1][j], dp[i+1][j+1]) + a[i][j]; /* HDU 2084 数塔 --- 入门DP */ #include <cstdio> const int N = 105; int dp[N][N]; int MAX(int a, int b){ return a > b ? a : b; } int main() { #ifdef _LOCAL freopen("D