天天看點

題解 UVA1376 【Animal Run】題解 UVA1376 【Animal Run】

題解 UVA1376 【Animal Run】

雙倍經驗題 q w q q q qwqqq qwqqq

如果您 A C AC AC 了本題,您可以去隔壁洛谷P4001狼抓兔子

(完全一樣的題目,隻是需要更改一下格式)

本題表面上看着像是網絡流最小割,但是網絡流蒟蒻不會的複雜度可能無法接受

是以本題是一個最短路

是以需要把圖轉為對偶圖

将原圖内圍成的每一個三角形看作一個虛點

因為要将起點和終點分割開,是以所練的路徑異地逆回購是從左或下到達右或上

是以需要 2 2 2 個點,一個點指向左和下的點,一個點被上或右的所有點指向

其餘的店指向與之相鄰的點

邊權為删除該邊的代價

是以很建好圖跑一遍 d i j k s t r a dijkstra dijkstra 就行了

P . S . P.S. P.S. 可能存在 n n n 或 m = 1 m=1 m=1 的情況,直接輸出所有邊中的最小值即可

具體細節見代碼(蒟蒻寫的可能還有一些複雜)

下面附上蒟蒻的代碼

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
inline int read()
{
    int r,s=0,c;
    for(;!isdigit(c=getchar());s=c);
    for(r=c^48;isdigit(c=getchar());(r*=10)+=c^48);
    return s^45?r:-r;
}
const int M=2100000,inf=2e9+7;
int n,m,minn,t;
inline int calc(int x,int y,int pos)
{//pos=1下,pos=2 上
    int ans=(2*m-2)*(x-1)+2*y-1;
    if(pos==2)ans++;
    return ans;
}
struct edge
{
    int to,next,val;
}mem[M<<2];
int head[M],cnt;
inline void add(int u,int v,int val)
{
    mem[++cnt].next=head[u];
    mem[cnt].to=v;
    mem[cnt].val=val;
    head[u]=cnt;
}
struct node
{
    int val,num;
    friend bool operator < (node a,node b)
    {
        return a.val>b.val;
    }
}f,ff;
int d[M];
bool vis[M];
inline void dijkstra(int s)
{
    int num=2*n*m-2*n-2*m+4;
    for(int i=1;i<=num;i++)
        d[i]=inf,vis[i]=0;
    priority_queue<node> q;
    f.num=s,f.val=0;
    d[s]=0;
    q.push(f);
    while(!q.empty())
    {
        f=q.top();
        q.pop();
        if(vis[f.num])continue;
        vis[f.num]=1;
        for(int i=head[f.num];i>0;i=mem[i].next)
        {
            int to=mem[i].to;
            if(d[to]>d[f.num]+mem[i].val)
            {
                d[to]=d[f.num]+mem[i].val;
                ff.num=to,ff.val=d[to];
                q.push(ff);
            }
        }
    }
}
int main()
{
    while(1)
    {

        minn=inf; 
        n=read(),m=read();
        if(n==0||m==0)
            return 0;
        memset(mem,0,sizeof(mem));
        memset(head,0,sizeof(head));
        cnt=0;
        int val;
        for(int i=1;i<=n;++i)//橫邊 
            for(int j=1;j<m;++j)
            {
                val=read();
                minn=min(minn,val);
                if(i==1)
                    add(calc(i,j,2),2*n*m-2*n-2*m+4,val);
                else if(i==n)
                    add(2*n*m-2*n-2*m+3,calc(i-1,j,1),val);
                else
                    add(calc(i-1,j,1),calc(i,j,2),val),add(calc(i,j,2),calc(i-1,j,1),val);
            }
        for(int i=1;i<n;++i)//縱邊
            for(int j=1;j<=m;++j)
            {
                val=read();
                minn=min(minn,val);
                if(j==1)
                    add(2*n*m-2*n-2*m+3,calc(i,j,1),val);
                else if(j==m)
                    add(calc(i,j-1,2),2*n*m-2*n-2*m+4,val);
                else
                    add(calc(i,j-1,2),calc(i,j,1),val),add(calc(i,j,1),calc(i,j-1,2),val);
            }
        for(int i=1;i<n;++i)//斜邊
            for(int j=1;j<m;++j)
            {
                val=read();
                minn=min(minn,val);
                add(calc(i,j,1),calc(i,j,2),val),add(calc(i,j,2),calc(i,j,1),val);
            }
        if(n==1||m==1)
        {
            printf("%d\n",minn);
            return 0;
        }
        dijkstra(2*n*m-2*n-2*m+3);
        t++;
        printf("Case %d: Minimum = %d\n",t,d[2*n*m-2*n-2*m+4]);
    }
    return 0;
}