zoukankan      html  css  js  c++  java
  • 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
    ",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
  • 相关阅读:
    try catch使用示例
    doxgen生成chm文档和乱码解决方法
    MFC中MessageBox()用法
    UML聚合与组合
    C#网络编程
    单元测试(NUnit)
    Autohotkey
    .NET中的并行
    System.Environment类的使用
    一键VHD
  • 原文地址:https://www.cnblogs.com/zstu-abc/p/3279130.html
Copyright © 2011-2022 走看看