UVALive 3661 Animal Run(最短路解最小割)

题意:动物要逃跑,工作人员要截断从START(左上角)到END(右下角)的道路,每条边权表示拦截该条道路需要多少工作人员。问最少需要多少人才能完成拦截。

通俗地讲,就是把图一分为二所造成消耗的最小值。

这里用最短路的方法解,主要是因为数据量太大,不能用最小割最大流还处理。

手动画一下这种“割”的形式,发现是从一条边到另一条边,即以边为“点”,在边与边之间见“边”,边上的权值为终点v(其实是一条边)的权值。(本来想直接用点权处理的,可coding的时候发现SPFA中的入队出队操作太繁琐,老老实实改边权了)。这里因为是以边为点,所以要对每条边编号,借用了昨天刚学到的ID()函数,很实用的。

最终的方案是整体从左下到右上,把START与END分成两部分。那么就以最左侧、最下侧的所有点为起点,做一遍最短路,求出最上侧、最右侧边所对应d[]数组的最小值,即为答案。

注:

1、因为是以边为点,共有少于n*m*3个“点”,共要建边(n-1)*(m-1)*2*3条“边”

2、不保证code是正确滴,这道题在uva挂了,难得能一次就跑出样例...偶已经很久木有一次AC了= =

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<vector>
  4 #include<queue>
  5 #include<algorithm>
  6 #define clr(a,m) memset(a,m,sizeof(a))
  7 #define rep(i,a,b) for(int i=a;i<=b;i++)
  8 using namespace std;
  9 
 10 const int MAXN=1111;
 11 const int INF =1e9;
 12 
 13 struct Edge{
 14     int v,next,c;
 15     Edge(){}
 16     Edge(int x,int y,int z):v(x),c(y),next(z){}
 17 }edge[MAXN*MAXN*6];
 18 
 19 int id[MAXN][MAXN][3],num;
 20 int grid[MAXN][MAXN][3];
 21 
 22 int head[MAXN*MAXN*3],tol;
 23 int vis[MAXN*MAXN*3],inq[MAXN*MAXN*3],d[MAXN*MAXN*3];
 24 
 25 void read(int n,int m)
 26 {
 27     rep(i,1,n)
 28         rep(j,1,m-1)
 29             scanf("%d",&grid[i][j][0]);
 30     rep(i,1,n-1)
 31         rep(j,1,m)
 32             scanf("%d",&grid[i][j][1]);
 33     rep(i,1,n-1)
 34         rep(j,1,m-1)
 35             scanf("%d",&grid[i][j][2]);
 36 }
 37 
 38 void init()
 39 {
 40     tol=0;
 41     clr(head,-1);
 42 
 43     num=0;
 44     clr(id,0);
 45 }
 46 
 47 void add(int u,int v,int cv,int cu)
 48 {
 49     edge[tol]=Edge(v,cv,head[u]);
 50     head[u]=tol++;
 51 
 52     edge[tol]=Edge(u,cu,head[v]);
 53     head[v]=tol++;
 54 }
 55 
 56 int ID(int i,int j,int k)
 57 {
 58     int& x=id[i][j][k];
 59     if(!x)x=++num;
 60     return x;
 61 }
 62 
 63 void build(int n,int m)//建图:原图在(n-1)*(m-1)个方格中各有两个三角形,在其内部以边为顶点建三角形,共构建(n-1)*(m-1)*2*3条边
 64 {
 65     init();
 66     rep(i,1,n-1){
 67         rep(j,1,m-1){
 68             add(ID(i,j,0),ID(i,j,2),grid[i][j][2],grid[i][j][0]);
 69             add(ID(i,j,0),ID(i,j+1,1),grid[i][j+1][1],grid[i][j][0]);
 70             add(ID(i,j,2),ID(i,j+1,1),grid[i][j+1][1],grid[i][j][2]);
 71 
 72             add(ID(i,j,1),ID(i,j,2),grid[i][j][2],grid[i][j][1]);
 73             add(ID(i,j,1),ID(i+1,j,0),grid[i+1][j][0],grid[i][j][1]);
 74             add(ID(i,j,2),ID(i+1,j,0),grid[i+1][j][0],grid[i][j][2]);
 75         }
 76     }
 77 }
 78 
 79 void SPFA(int n,int m)
 80 {
 81     priority_queue<int,vector<int>,greater<int> >q;
 82     clr(inq,0);
 83     rep(i,1,num)
 84         d[i]=INF;
 85     rep(i,1,n-1){
 86         int s=id[i][1][1];
 87         d[s]=grid[i][1][1];
 88         q.push(s);
 89         vis[s]=true;
 90     }
 91     rep(j,1,m-1){
 92         int s=id[n][j][0];
 93         d[s]=grid[n][j][0];
 94         q.push(s);
 95         vis[s]=true;
 96     }
 97     while(!q.empty())
 98     {
 99         int u=q.top();q.pop();
100         vis[u]=false;
101         for(int i=head[u];i!=-1;i=edge[i].next)
102         {
103             int v=edge[i].v;
104             int c=edge[i].c;
105             if(d[v]>d[u]+c){
106                 d[v]=d[u]+c;
107                 if(!vis[v]){
108                     q.push(v);
109                     vis[v]=true;
110                 }
111             }
112         }
113     }
114 }
115 
116 void print(int n,int m,int cnt)
117 {
118     int ans=INF;
119     rep(j,1,m-1)
120         ans=min(ans,d[id[1][j][0]]);
121     rep(i,1,n-1)
122         ans=min(ans,d[id[i][m][1]]);
123     printf("Case %d: Minimum = %d\n",cnt,ans);
124 }
125 
126 int main()
127 {
128     int n,m,cnt=0;
129     while(scanf("%d%d",&n,&m)==2&&n)
130     {
131         read(n,m);
132         build(n,m);
133         SPFA(n,m);
134         print(n,m,++cnt);
135     }
136     return 0;
137 }
View Code

 

转载于:https://www.cnblogs.com/zstu-abc/p/3279130.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值