2020/10/11

kuangbin网络流4题

///链接:https://vjudge.net/problem/UVA-10480
/*题意: n个结点,m路径,现在让s和t号结点不要连接,破坏一条点的花费为k。
  题解:最小割。但是注意此题有个区别,他是破坏点,所以我们应该拆点,然后在跑。
*/

#include"stdio.h"
#include"string.h"
#include"stack"
#include"map"
#include"math.h"
#include"iostream"
#include"string"
#include"vector"
#include"queue"
#include"algorithm"
using namespace std;
#define OK printf("
");
#define Debug printf("this_ok
");
#define INF 1e18
typedef long long ll;
#define scanll(a,b) scanf("%lld%lld",&a,&b);
#define scanl(a) scanf("%lld",&a);
#define printl(a,b) if(b == 0) printf("%lld ",a); else printf("%lld
",a);
#define print_int(a,b) if(b == 0) printf("%d ",a); else printf("%d
",a);
typedef pair<int,int> PII;

inline int read(){
    int s = 0, w = 1; char ch = getchar();
    while(ch < '0' || ch > '9')   { if(ch == '-') w = -1; ch = getchar(); }
    while(ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar(); }
    return s * w;
}
const ll mod = 998244353;
const int N = 200000,M = 800000;
const  double pi = acos(-1);
const int inf = 1 << 29;
const int dirx[4] = {-1,0,1,0};
const int diry[4] = {0,1,0,-1};
int n,m,t,s,tot;
ll maxflow,sum;
int head[N],ver[M],Next[M],edge[M],d[N];
int w[N];
queue<int> q;
map<string,int> Q;
void add(int x,int y,int z){
    ver[++ tot] = y; Next[tot] = head[x];  edge[tot] = z; head[x] = tot;
    ver[++ tot] = x; edge[tot] = 0; Next[tot] = head[y]; head[y] = tot;
}
void add1(int x,int y,int z){
    ver[++ tot] = y; Next[tot] = head[x];  edge[tot] = z; head[x] = tot;
    ver[++ tot] = x; edge[tot] = 0; Next[tot] = head[y]; head[y] = tot;
}
bool bfs(){
    memset(d,0,sizeof(d));
    while(q.size())q.pop();
    q.push(s); d[s] = 1;
    while(q.size()){
        int x = q.front(); q.pop();
        for(int i = head[x]; i; i = Next[i])
        if(edge[i] && !d[ver[i]]){
            q.push(ver[i]); d[ver[i]] = d[x] + 1;
            if(ver[i] == t) return 1;
        }
    }
    return 0;
}

int dinic(int x,ll flow){
    if(x == t) return flow;
    ll rest = flow,k;
    for(int i = head[x]; i && rest; i = Next[i]){
         if(edge[i] && d[ver[i]] == d[x] + 1){
            k = dinic(ver[i],min(rest,(ll)edge[i]));
            if(!k) d[ver[i]] = 0;
            edge[i] -= k;
            edge[i ^ 1] += k;
            rest -= k;
         }
    }
    return flow - rest;
}
int main(){
    while(~scanf("%d",&n)){
        m = read();
        for(int i = 0; i <= n + n + 2; i ++) head[i] = 0;
        tot = 1;s = read(); t = read();t += n;
        for(int i = 1; i <= n; i ++){
            int x = read();
            add1(i,i + n,x);
        }
        for(int i = 1; i <= m; i ++){
           int x = read(),y = read();
           add(x + n,y,inf);
           add(y + n,x,inf);
        }
        ll flow = 0; maxflow = 0;
        while(bfs())
            while(flow = dinic(s,inf)) maxflow += flow;
        printf("%lld
",maxflow);
    }
}
/*
3
1 2 3
2
2 6
*/


///链接:https://vjudge.net/problem/UVA-10480
/*题意: n个结点,m路径,现在让1和2号结点不要连接,破坏一条路径的花费为k。
  题解:最小割,输出路径的话,x和y一开始有路径,x只和1号点连接,y只和2号点连接,那么就是割边。
  鉴于此,本题我们用邻接矩阵存储更为方便;
*/

#include"stdio.h"
#include"string.h"
#include"stack"
#include"map"
#include"math.h"
#include"iostream"
#include"vector"
#include"queue"
#include"algorithm"
using namespace std;
#define OK printf("
");
#define Debug printf("this_ok
");
#define INF 0x3f3f3f3f
typedef long long ll;
#define scanll(a,b) scanf("%lld%lld",&a,&b);
#define scanl(a) scanf("%lld",&a);
#define printl(a,b) if(b == 0) printf("%lld ",a); else printf("%lld
",a);
#define print_int(a,b) if(b == 0) printf("%d ",a); else printf("%d
",a);
typedef pair<int,int> PII;

inline int read(){
    int s = 0, w = 1; char ch = getchar();
    while(ch < '0' || ch > '9')   { if(ch == '-') w = -1; ch = getchar(); }
    while(ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar(); }
    return s * w;
}
const ll mod = 998244353;
const int N = 500010,M = 500010;
const int inf = 1 << 29;
const int maxn=1e3+10;
int n,m;
int mp[maxn][maxn];//初始流量
int flow[maxn][maxn];//最大流
int path[maxn];//记录路径
int a[maxn];//i点在最大流中的流量
int start,End;
int x[maxn],y[maxn];
int maxflow()
{
    queue<int> q;
    memset(flow,0,sizeof flow);
    int max_flow=0;
    while(true){
        memset(a,0,sizeof a);//清空标记
        a[start]=INF;//源点权值无限大
        while(!q.empty())   q.pop();
        q.push(start);
        while(!q.empty()){
            int temp=q.front();
            q.pop();
            for(int i=1;i<=n;i++){
                //未走过且流量小于他的权值
                if(!a[i]&&flow[temp][i]<mp[temp][i])
                {
                    path[i]=temp;//记录前一个点
                    a[i]=min(a[temp],mp[temp][i]-flow[temp][i]);
                    q.push(i);
                }
            }

        }
        if(a[End]==0)   break;
        //更新剩余网络
        for(int i=End;i!=start;i=path[i]){
            flow[path[i]][i]+=a[End];//反向边加
            flow[i][path[i]]-=a[End];//正向边减
        }
        max_flow+=a[End];
    }
    return max_flow;
}
int main()
{
    while(~scanf("%d%d",&n,&m)){
        if(n == 0) break;
        memset(mp,0,sizeof mp);
        for(int i=1;i<=m;i++)
        {
            int u = read(),v = read(),w = read();
            mp[u][v]=mp[v][u]=w;///无向路径
            x[i]=u; y[i]=v;
        }
        start=1;End=2;
        int flow=maxflow();
        for(int i=1;i<=m;i++){//枚举每一条边的两个点
            //有一点的权值为0,说明当前点被删除
            if((!a[x[i]]&&a[y[i]])||(a[x[i]]&&!a[y[i]]))
            printf("%d %d
",x[i],y[i]);
        }
        printf("
");
    }
    return 0;
}
///链接:http://acm.hdu.edu.cn/showproblem.php?pid=4280
/*题意: 在最西边的点走到最东边的点最大容量。
  题解:ISAP模板题,Dinic过不了。
*/

#include"stdio.h"
#include"string.h"
#include"stack"
#include"map"
#include"math.h"
#include"iostream"
#include"string"
#include"vector"
#include"queue"
#include"algorithm"
using namespace std;
#define OK printf("
");
#define Debug printf("this_ok
");
#define INF 1e18
typedef long long ll;
#define scanll(a,b) scanf("%lld%lld",&a,&b);
#define scanl(a) scanf("%lld",&a);
#define printl(a,b) if(b == 0) printf("%lld ",a); else printf("%lld
",a);
#define print_int(a,b) if(b == 0) printf("%d ",a); else printf("%d
",a);
typedef pair<int,int> PII;

inline int read(){
    int s = 0, w = 1; char ch = getchar();
    while(ch < '0' || ch > '9')   { if(ch == '-') w = -1; ch = getchar(); }
    while(ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar(); }
    return s * w;
}
const ll mod = 998244353;
const int N = 200000,M = 800000;
const  double pi = acos(-1);
const int inf = 1 << 29;
const int dirx[4] = {-1,0,1,0};
const int diry[4] = {0,1,0,-1};
int n,m,t,s,tot;
ll maxflow,sum;
int head[N],ver[M],Next[M],edge[M],d[N];
int w[N];
queue<int> q;
map<string,int> Q;
void add(int x,int y,int z){
    ver[++ tot] = y; Next[tot] = head[x];  edge[tot] = z; head[x] = tot;
    ver[++ tot] = x; edge[tot] = z; Next[tot] = head[y]; head[y] = tot;
}

bool bfs(){
    memset(d,0,sizeof(d));
    while(q.size())q.pop();
    q.push(s); d[s] = 1;
    while(q.size()){
        int x = q.front(); q.pop();
        for(int i = head[x]; i; i = Next[i])
        if(edge[i] && !d[ver[i]]){
            q.push(ver[i]); d[ver[i]] = d[x] + 1;
            if(ver[i] == t) return 1;
        }
    }
    return 0;
}

int dinic(int x,ll flow){
    if(x == t) return flow;
    ll rest = flow,k;
    for(int i = head[x]; i && rest; i = Next[i]){
         if(edge[i] && d[ver[i]] == d[x] + 1){
            k = dinic(ver[i],min(rest,(ll)edge[i]));
            if(!k) d[ver[i]] = 0;
            edge[i] -= k;
            edge[i ^ 1] += k;
            rest -= k;
         }
    }
    return flow - rest;
}
int main(){
    int T = read();
    while(T --){
        n = read(); m = read();
        tot = 1;s = 1; t = 1;
        int tmax = -inf, tmin = inf;
         s = t= 1;
        for(int i = 1; i <= n; i ++) {
            int x = read(),y = read();
            if(x >= tmax) tmax = x, t = i;
            if(x <= tmin) tmin = x, s = i;
            head[i] = 0;
         }
        for(int i = 1; i <= m; i ++){
           int x = read(),y = read(),w = read();
           add(x,y,w);
        }
        ll flow = 0; maxflow = 0;
        while(bfs())
            while(flow = dinic(s,inf)) maxflow += flow;
        printf("%lld
",maxflow);
    }
}
/*
3
1 2 3
2
2 6
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <vector>
#include <map>
#include <set>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
typedef long long LL;
struct Edge {
    int u, v;
    LL cap;
    Edge () {}
    Edge (int u, int v, LL cap) : u(u), v(v), cap(cap) {}
}edge[N*4];
vector<int> G[N];
int dis[N], cur[N], num[N], pre[N], tot, S, T;

void Add(int u, int v, int cap) {
    edge[tot] = Edge(u, v, cap);
    G[u].push_back(tot++);
    edge[tot] = Edge(v, u, cap);
    G[v].push_back(tot++);
}

int BFS() { // 逆向BFS
    memset(dis, -1, sizeof(dis));
    queue<int> que; que.push(T);
    dis[T] = 0;
    while(!que.empty()) {
        int u = que.front(); que.pop();
        for(int i = 0; i < G[u].size(); i++) {
            Edge &e = edge[G[u][i]];
            if(dis[e.v] == -1) {
                dis[e.v] = dis[u] + 1;
                que.push(e.v);
            }
        }
    }
    return ~dis[S];
}

int DFS() { // 通过pre数组回溯更新流量
    int u = T; int flow = INF;
    while(u != S) {
        Edge &e = edge[pre[u]];
        if(e.cap < flow) flow = e.cap;
        u = e.u;
    } u = T;
    while(u != S) {
        Edge& e1 = edge[pre[u]];
        Edge& e2 = edge[pre[u]^1];
        e1.cap -= flow; e2.cap += flow;
        u = e1.u;
    }
    return flow;
}

int ISAP(int n) {
    if(!BFS()) return 0; // 从汇点到源点逆向BFS初始化dis数组
    memset(num, 0, sizeof(num));
    memset(cur, 0, sizeof(cur)); // 当前弧优化
    for(int i = 1; i <= n; i++)
        if(~dis[i]) num[dis[i]]++; // 当前距离为dis[i]的结点数
    int ans = 0, u = S;
    while(dis[S] < n) {
        if(u == T) ans += DFS(), u = S; //  回溯之前的结点并把更新流量
        int flag = 0;
        for(int i = 0; i < G[u].size(); i++) {
            Edge &e = edge[G[u][i]];
            if(dis[e.v] + 1 == dis[u] && e.cap > 0) { // 可以增广
                pre[e.v] = G[u][i]; cur[u] = i;
                flag = 1; u = e.v;
                break;
            }
        }
        if(!flag) { // 不能增广,retreat
            if(--num[dis[u]] == 0) break; // gap优化
            int md = n;
            for(int i = 0; i < G[u].size(); i++) {
                Edge &e = edge[G[u][i]];
                if(e.cap > 0 && dis[e.v] < md) {
                    md = dis[e.v]; cur[u] = i;
                }
            }
            num[dis[u] = md + 1]++;
            if(u != S) u = edge[pre[u]].u;
        }
    }
    return ans;
}

int main() {
    int t;
    scanf("%d", &t);
    while(t--) {
        int n, m;
        scanf("%d%d", &n, &m);
        tot = 0; for(int i = 0; i <= n; i++) G[i].clear();
        int u, v, c, west = 100000000, east = -10000000;
        for(int i = 1; i <= n; i++) {
            scanf("%d%d", &u, &v);
            if(west > u) west = u, S = i;
            if(east < u) east = u, T = i;
        }
        for(int i = 1; i <= m; i++) {
            scanf("%d%d%d", &u, &v, &c);
            Add(u, v, c); // 无向图的话反向边的cap也是c
        }
        printf("%d
", ISAP(n));
    }
    return 0;
}
*/

///链接:https://vjudge.net/problem/POJ-1087
/*题意:  有m个设备需要插座(给出了每个设备需要的插座型号),但是现在只有n个插座(任意两个插座类型不相同,因为题目说每种类型插座就一个),且给你k个转换器(转换器(u,v)可以使得插座v转接到u上),问你最多有几个设备没有插座可用?
  题解:建图:
       源点s(编号0)到每个设备i有边 (s,i,1).
       每个插座到j到汇点t(编号n+m+1)有边 (j,t,1)
       如果设备i对应的插座是j,那么有边(i,j,1)
       如果转换器对应(u,v)(说明可以把插座v转接到u上),那么有边(u,v,INF) (因为转换器无限个,且它可以把原本需要u插座的电器连到v插座上)
*/

#include"stdio.h"
#include"string.h"
#include"stack"
#include"map"
#include"math.h"
#include"iostream"
#include"string"
#include"vector"
#include"queue"
#include"algorithm"
using namespace std;
#define OK printf("
");
#define Debug printf("this_ok
");
#define INF 1e18
typedef long long ll;
#define scanll(a,b) scanf("%lld%lld",&a,&b);
#define scanl(a) scanf("%lld",&a);
#define printl(a,b) if(b == 0) printf("%lld ",a); else printf("%lld
",a);
#define print_int(a,b) if(b == 0) printf("%d ",a); else printf("%d
",a);
typedef pair<int,int> PII;

inline int read(){
    int s = 0, w = 1; char ch = getchar();
    while(ch < '0' || ch > '9')   { if(ch == '-') w = -1; ch = getchar(); }
    while(ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar(); }
    return s * w;
}
const ll mod = 998244353;
const int N = 50010,M = 300010;
const  double pi = acos(-1);
const int inf = 1 << 29;
const int dirx[4] = {-1,0,1,0};
const int diry[4] = {0,1,0,-1};
int n,m,t,s,tot;
ll maxflow,sum;
int head[N],ver[M],Next[M],edge[M],d[N];
int w[N];
queue<int> q;
map<string,int> Q;
void add(int x,int y,int z){
    ver[++ tot] = y; Next[tot] = head[x];  edge[tot] = z; head[x] = tot;
    ver[++ tot] = x; edge[tot] = 0; Next[tot] = head[y]; head[y] = tot;
}

bool bfs(){
    memset(d,0,sizeof(d));
    while(q.size())q.pop();
    q.push(s); d[s] = 1;
    while(q.size()){
        int x = q.front(); q.pop();
        for(int i = head[x]; i; i = Next[i])
        if(edge[i] && !d[ver[i]]){
            q.push(ver[i]); d[ver[i]] = d[x] + 1;
            if(ver[i] == t) return 1;
        }
    }
    return 0;
}

int dinic(int x,ll flow){
    if(x == t) return flow;
    ll rest = flow,k;
    for(int i = head[x]; i && rest; i = Next[i]){
         if(edge[i] && d[ver[i]] == d[x] + 1){
            k = dinic(ver[i],min(rest,(ll)edge[i]));
            if(!k) d[ver[i]] = 0;
            edge[i] -= k;
            edge[i ^ 1] += k;
            rest -= k;
         }
    }
    return flow - rest;
}
int main(){
    n = read();
    tot = 1;int top = 0; s = 0; t = 510;
    int p1[120] = {0},p2[120] = {0};
    for(int i = 1; i <= n; i ++){
        char str; cin >> str;
        p1[str - 'A' + 1] ++;
    }
    for(int i = 1; i < 120; i ++){
        if(!p1[i]) continue;
        add(i,t,p1[i]);
    }
    m = read();
    for(int i = 1; i <= m; i ++){
        string name; char str;
        cin >> name >> str;
        p2[str - 'A' + 1] ++;
    }
    for(int i = 1; i < 120; i ++){
        if(!p2[i]) continue;
        add(s,i + 120,p2[i]);
       // add(i + 120,i,inf);
    }
    int q = read();
    for(int i = 1; i <= q; i ++){
        char s1,s2; cin >> s1 >> s2;
        add(s1 - 'A' + 1 + 120,s2 - 'A' + 1 + 120,inf);
    }
   for(int i = 1; i < 120; i ++) add(i + 120,i,inf);
    ll flow = 0;
    while(bfs())
        while(flow = dinic(s,inf)) maxflow += flow;
    printf("%lld
",m - maxflow);
}
/*
3
1 2 3
2
2 6
*/

  

原文地址:https://www.cnblogs.com/yrz001030/p/13799766.html