[acm/icpc2016ChinaFinal][CodeforcesGym101194] Mr.Panda and TubeMaster

来源:互联网 发布:水经注软件 谷歌 编辑:程序博客网 时间:2024/06/08 14:56

这个题从范围来看,不难想到跟费用流有关系。但感觉跟费用流联系起来还是很难呀。拆点,这个题可以看成是给每个点找一个后继点,这一点是解题的关键。然后就是要黑白染色定向,定向这个点能走横边还是竖边,定向之后,神奇的发现所有的边都被连了有且仅有一次,这种套路估计大佬已经习以为常了吧。然后对于那些非限制格子,自己的入点连出点,保证可以不连接。然后直接看代码吧。

#include <bits/stdc++.h>using namespace std;typedef long long LL;const int MAXN = 2000+5;const int inf = 1e9;int n,m;int s,e;int cnt,head[MAXN];struct node{    int u,v,w,f,next;} edge[50000];void init(){    cnt = 0;    for(int i = 0; i <= e; ++i)head[i] = -1;}void add(int u,int v,int w,int f){    edge[cnt].u = u;    edge[cnt].v = v;    edge[cnt].w = w;    edge[cnt].f = f;    edge[cnt].next = head[u];    head[u] = cnt++;    edge[cnt].u = v;    edge[cnt].v = u;    edge[cnt].w = -w;    edge[cnt].f = 0;    edge[cnt].next = head[v];    head[v] = cnt++;}bool vis[MAXN];int dis[MAXN],pre[MAXN];bool spfa(){    for(int i = 0; i <= e; ++i)    {        dis[i] = -inf;        pre[i] = -1;    }    queue<int>q;    q.push(s);    dis[s] = 0;    while(!q.empty())    {        int u = q.front();        q.pop();        vis[u] = 0;        for(int i = head[u]; i != -1; i = edge[i].next)        {            int v = edge[i].v;            int w = edge[i].w;            int f = edge[i].f;            if(f > 0 && dis[v] < dis[u] + w)            {                dis[v] = dis[u] + w;                pre[v] = i;                if(!vis[v])                {                    vis[v] = 1;                    q.push(v);                }            }        }    }    if(pre[e] == -1)return 0;    return 1;}void get_mincost(){    int max_flow = 0,min_cost = 0;    while(spfa())    {        int p = pre[e];        int flow = inf;        while(p != -1)        {            flow = min(flow,edge[p].f);            p = pre[edge[p].u];        }        max_flow += flow;        min_cost += flow*dis[e];        p = pre[e];        while(p != -1)        {            edge[p].f -= flow;            edge[p^1].f += flow;            p = pre[edge[p].u];        }    }    if(max_flow != n*m)puts("Impossible");    else printf("%d\n",min_cost);}int scorec[40][40],scorer[40][40];int L[40][40],R[40][40];bool tu[40][40];int main(){    int t,ca = 0;    scanf("%d",&t);    while(t--)    {        scanf("%d%d",&n,&m);        int id = 0;        for(int i = 0; i < n; ++i)            for(int j = 0; j < m; ++j)L[i][j] = ++id,R[i][j] = ++id;        s = 0,e = ++id;        for(int i = 0; i < n; ++i)            for(int j = 0; j < m-1; ++j)scanf("%d",&scorec[i][j]);        for(int i = 0; i < n-1; ++i)            for(int j = 0; j < m; ++j)scanf("%d",&scorer[i][j]);        int E;        int x,y;        scanf("%d",&E);        while(E--)        {            scanf("%d%d",&x,&y);            x--,y--;            tu[x][y] = 1;        }        init();        for(int i = 0; i < n; ++i)            for(int j = 0; j < m; ++j)            {                if((i+j)%2)                {                    if(j+1 < m)add(L[i][j],R[i][j+1],scorec[i][j],1);                    if(j-1 >= 0)add(L[i][j],R[i][j-1],scorec[i][j-1],1);                }                else                {                    if(i+1 < n)add(L[i][j],R[i+1][j],scorer[i][j],1);                    if(i-1 >= 0)add(L[i][j],R[i-1][j],scorer[i-1][j],1);                }            }        for(int i = 0; i < n; ++i)            for(int j = 0; j < m; ++j)            {                add(s,L[i][j],0,1);                add(R[i][j],e,0,1);                if(!tu[i][j])add(L[i][j],R[i][j],0,1);                else tu[i][j] = 0;            }        printf("Case #%d: ",++ca);        get_mincost();    }    return 0;}
阅读全文
0 0