codeforces #304 E 546E E. Soldier and Traveling(最大流)

来源:互联网 发布:matlab 数据反转 编辑:程序博客网 时间:2024/05/17 22:53

题目链接:

点击打开链接

题目大意:

给出一个无向图,每个点有一个值,只能给它周围的一个点一些值,然后达到目标的点权

题目分析:

考虑到点之间的值相互交换,想到了网络流,那么对于每个点,先要拆点,一个点代表起始状态,另一个代表目标状态,也就是同一个点拆成的两个点一定是可以链接,而且权值就是a[i],然后对于每条边,将起始点和目标点连接,因为目标点的流量由起始点的流量和与它相连的其他起始点的流量决定,所以可以利用最大流做,如果最后得到的最大流等于目标点的总数,那么就能完成题目要求,否则不能,然后源点要连向起始点提供流量,目标点连向汇点,容量为目标的点权值,那么走的流量记录在起始点和目标点之间,利用汇点判断能否成功,然后利用边的流量来记录,然后直接输出即可

代码如下:

拆完点之后,套模板.........

#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>#include <queue>#define N 207#define INF 0x3f3f3f3f#define MAX 10000using namespace std;int n,m,u,v;int sum1,sum2;int a[N];int b[N];int s[N][N];int d[N];bool bfs ( ){    queue<int> q;    memset ( d , -1 , sizeof ( d ) );    d[0] = 0;    q.push (0);    while ( !q.empty() )    {        int v = q.front();        q.pop();        for ( int i = 0 ; i <= 2*n+1 ; i++ )            if ( d[i] == -1 && s[v][i] )            {                d[i] = d[v]+1;                q.push ( i );            }    }    return d[2*n+1] != -1;}int dfs ( int v , int cur_flow ){    //cout << v << endl;    int dt = cur_flow;    if ( v == 2*n+1 ) return cur_flow;    for ( int i = 0 ; i <= 2*n+1 ; i++ )    {        if ( s[v][i] > 0 && d[v]+1 == d[i] )        {            int flow = dfs ( i , min ( dt , s[v][i] ) );            s[v][i] -= flow;            s[i][v] += flow;            dt -= flow;        }    }    return cur_flow - dt;}void dinic ( ){    int cur_flow , ans = 0;    //int cnt = 1000000;    while ( bfs() )    {        while ( cur_flow = dfs ( 0 , INF ) )                ans += cur_flow;    }    //cout << "OKAY!" << endl;    if ( ans != sum1 )    {        puts("NO");        return;    }    puts("YES");    for ( int i = 1 ; i <= n ; i++ )    {        for ( int j = n+1 ; j <= 2*n ; j++ )            if ( !s[i][j] )                printf ( "0 " );            else             printf ( "%d " , INF - s[i][j] );        puts("");    }}int main ( ){    while ( ~scanf ( "%d%d" , &n , &m ))    {        sum1 = 0 , sum2 = 0;        memset ( s , 0 , sizeof ( s ) );        for ( int i = 1 ; i <= n ; i++ )        {            scanf ( "%d" , &a[i] );            sum1 += a[i];            s[0][i] = a[i];            s[i][n+i] = INF;        }        for ( int i = 1 ; i <= n ; i++ )        {            scanf ( "%d" , &b[i] );            sum2 += b[i];            s[n+i][2*n+1] = b[i];        }        while ( m-- )        {            int u,v;            scanf ( "%d%d" , &u , &v );            s[u][v+n] = INF;            s[v][u+n] = INF;        }        if ( sum1 != sum2 )        {            puts("NO");            continue;        }        dinic();    }}


0 0
原创粉丝点击