[bzoj2521][Shoi2010]最小生成树 最小割

来源:互联网 发布:sql select语句例子 编辑:程序博客网 时间:2024/05/29 02:30

2521: [Shoi2010]最小生成树

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

Description

Secsa最近对最小生成树问题特别感兴趣。他已经知道如果要去求出一个n个点、m条边的无向图的最小生成树有一个Krustal算法和另一个Prim的算法。另外,他还知道,某一个图可能有多种不同的最小生成树。例如,下面图 3中所示的都是图 2中的无向图的最小生成树:

当然啦,这些都不是今天需要你解决的问题。Secsa想知道对于某一条无向图中的边AB,至少需要多少代价可以保证AB边在这个无向图的最小生成树中。为了使得AB边一定在最小生成树中,你可以对这个无向图进行操作,一次单独的操作是指:先选择一条图中的边 P1P2,再把图中除了这条边以外的边,每一条的权值都减少1。如图 4所示就是一次这样的操作:

Input

输入文件的第一行有3个正整数n、m、Lab分别表示无向图中的点数、边数、必须要在最小生成树中出现的AB边的标号。
接下来m行依次描述标号为1,2,3…m的无向边,每行描述一条边。每个描述包含3个整数x、y、d,表示这条边连接着标号为x、y的点,且这条边的权值为d。
输入文件保证1<=x,y<=N,x不等于y,且输入数据保证这个无向图一定是一个连通图。

Output

输出文件只有一行,这行只有一个整数,即,使得标号为Lab边一定出现最小生成树中的最少操作次数。

Sample Input

4 6 1
1 2 2
1 3 2
1 4 3
2 3 2
2 4 4
3 4 5

Sample Output

1

HINT

1个样例就是问题描述中的例子。


1<=n<=500,1<=M<=800,1<=D<10^6

Source

S:u[id]
T:v[id]
u[i]->v[i]:w[id]-w[i]+1
需要解释吗
好吧
其它边-1相当于这条加一(这只对题目理解有帮助)
如果id这条边在最小生成树上
那么比他小的边加入后u[id]与v[id]不联通
如果联通,就去割掉某些边使其不联通
代价为边权差+1
#include<iostream>#include<cstring>#include<cstdio>#define INF 0x7fffffffusing namespace std;const int N = 30005;int ans=0, tot=0;int n, m, S, T, cnt = 1, id;int q[N], last[N], h[N], cur[N], u[N], v[N], w[N];struct Edge{int to,next,v;}e[1000005];void insert( int u, int v, int w ){e[++cnt].to = v; e[cnt].v = w; e[cnt].next = last[u]; last[u] = cnt;e[++cnt].to = u; e[cnt].v = 0; e[cnt].next = last[v]; last[v] = cnt;}bool bfs(){    int head = 0, tail = 1;    memset(h,-1,sizeof(h));    q[0] = S; h[S] = 0;    while( head != tail ){        int u = q[head++];        for( int i = last[u]; i; i = e[i].next ){            int v = e[i].to;            if( h[v] == -1 && e[i].v ) {                q[tail++] = v;                h[v] = h[u] + 1;            }        }    }    return h[T] != -1;}int dfs( int x, int f ){    if( x == T ) return f;    int w,used=0;    for( int i = cur[x]; i; i = e[i].next ){        int v = e[i].to;        if( h[v] == h[x] + 1 ){            w = dfs( v, min( f-used, e[i].v ) );            used += w; e[i].v -= w; e[i^1].v += w;            if( e[i].v ) cur[x] = i;             if( used == f ) return f;        }    }    if( !used ) h[x] = -1;    return used;}void dinic(){    while( bfs() ){        for( int i = 0; i <= n+1; i++ ) cur[i] = last[i];         ans += dfs( S, INF );     }}int main(){scanf("%d%d%d", &n, &m, &id);for( int i = 1; i <= m; i++ ) scanf("%d%d%d", &u[i], &v[i], &w[i]);S = u[id]; T= v[id];for( int i = 1; i <= m; i++ )if( w[i] <= w[id] && i^id ){insert( u[i], v[i], w[id]-w[i]+1 );insert( v[i], u[i], w[id]-w[i]+1 );}dinic();printf("%d\n", ans);return 0;}


原创粉丝点击