UVALive 3661 Animal Run(平面图最小割,边为节点+最短路)

来源:互联网 发布:c语言字符串数组拷贝 编辑:程序博客网 时间:2024/05/16 09:48

题目:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1662

题目大意:给你一个 n*m 的平面图,除了方格的边线外还增加了一个,左上角到右下角,这些线都是双向边。有一群动物从整个图的左上角要跑到右下角去,然后要去拦截他们跑到那里,每条边上的权值是拦截这条边所需的人数。问你拦截他们最少的人数。

解题思路:本来是挺像最小割,可是太慢。这题的构图实在是太巧妙了!其实题目就是从左下边界拦到右上边界的最小权值和问题。把每条边看成一个节点,每个三角形的三条道路两两直接相连,只是就是得到另外一个边和点都是 O(nm)的带权图了。然后把左/下边界的所有点(原图里是边)加到队列里作为超级源跑最短路,跑完后取上/右边界的点的最小值就行了。关于上面三角形这样建边,需要好好想想,这样能做到把一个小方格从左上到右下都封死。另外还有边编号那里也需要动点脑筋,挺烦的,我编的方式也挺烦的。。

        很好的一道建边题啊,不管你想到没有,反正我是没有想到。。。= =

代码如下:

#include<cstdio>#include<cstring>#include<queue>#include<algorithm>using namespace std;const int INF = 0x0fffffff;const int MAXN = 1111*1111*3;const int MAXM = MAXN*2;int cc;struct Edge{    int t,next;} edge[MAXM<<1];int tot,head[MAXN];void add_edge(int s,int t){    edge[tot].t = t;    edge[tot].next = head[s];    head[s] = tot++;}void init(){    tot = 0;    memset(head,-1,sizeof(head));}int id[3][1111][1111];int get_id(int kind,int x,int y){    return id[kind][x][y];}int val[MAXN];bool done[MAXN];int dis[MAXN];struct Node{    int id,val;    Node(int a,int b)    {        id = a;        val = b;    }    bool operator < (const Node& tmp) const    {        return val > tmp.val;    }};void dij(int n,int m){    priority_queue<Node> q;    memset(done,0,sizeof(done));    for(int i = 0;i < cc;i++)        dis[i] = INF;    for(int i = 0;i < n-1;i++)    {        int id = get_id(1,i,0);        dis[id] = val[id];        q.push(Node(id,val[id]));    }    for(int j = 0;j < m-1;j++)    {        int id = get_id(0,n-1,j);        dis[id] = val[id];        q.push(Node(id,val[id]));    }    while(!q.empty())    {        Node cur = q.top();        q.pop();        if(done[cur.id]) continue;        done[cur.id] = 1;        for(int i = head[cur.id];i != -1;i = edge[i].next)        {            int t = edge[i].t;            int tmp = dis[cur.id]+val[t];            if(dis[t] > tmp)            {                dis[t] = tmp;                q.push(Node(t,tmp));            }        }    }}void add(int n,int m){    init();    for(int i = 0;i < n;i++)        for(int j = 0;j < m-1;j++)        {            if(i > 0)            {                add_edge(get_id(0,i,j),get_id(1,i-1,j));                add_edge(get_id(0,i,j),get_id(2,i-1,j));            }            if(i != n-1)            {                add_edge(get_id(0,i,j),get_id(1,i,j+1));                add_edge(get_id(0,i,j),get_id(2,i,j));            }        }        for(int i = 0;i < n-1;i++)            for(int j = 0;j < m;j++)            {                if(j > 0)                {                    add_edge(get_id(1,i,j),get_id(0,i,j-1));                    add_edge(get_id(1,i,j),get_id(2,i,j-1));                }                if(j != m-1)                {                    add_edge(get_id(1,i,j),get_id(0,i+1,j));                    add_edge(get_id(1,i,j),get_id(2,i,j));                }            }        for(int i = 0;i < n-1;i++)            for(int j = 0;j < m-1;j++)            {                add_edge(get_id(2,i,j),get_id(0,i+1,j));                add_edge(get_id(2,i,j),get_id(1,i,j));                add_edge(get_id(2,i,j),get_id(0,i,j));                add_edge(get_id(2,i,j),get_id(1,i,j+1));            }}int main(){    int ca = 0;    int n,m;    while(~scanf("%d%d",&n,&m) && (n+m))    {        cc = 0;        for(int i = 0;i < n;i++)            for(int j = 0;j < m-1;j++)            {                id[0][i][j] = cc++;                scanf("%d",&val[get_id(0,i,j)]);            }        for(int i = 0;i < n-1;i++)            for(int j = 0;j < m;j++)            {                id[1][i][j] = cc++;                scanf("%d",&val[get_id(1,i,j)]);            }        for(int i = 0;i < n-1;i++)            for(int j = 0;j < m-1;j++)            {                id[2][i][j] = cc++;                scanf("%d",&val[get_id(2,i,j)]);            }        add(n,m);        dij(n,m);        int ans = INF;        for(int j = 0;j < m-1;j++)            ans = min(ans,dis[get_id(0,0,j)]);        for(int i = 0;i < n-1;i++)            ans = min(ans,dis[get_id(1,i,m-1)]);        printf("Case %d: Minimum = %d\n",++ca,ans);    }    return 0;}


0 0
原创粉丝点击