uvalive 3661 Animal Run

题意:

一群动物想从动物园逃离,从一个图的左上角出发,只有到达右下角才能彻底逃离。

动物园的管理者为了防止他们逃跑,安排了若干人在路上防守。

现在问最少需要花多少人能够封锁动物逃跑的路线。

思路:

简单画一画知道,就是找一个边的集合把整个图分成两个部分,且要求这些边的权值最小,这是著名的最小割问题(虽然我没有学过。

不过可以用最短路解决。

经过尝试可以知道,从下到上的连线,从左到右的连线,从左到上的连线以及从下到右的连线均可以到达目的,其它的就不行,比如从下到左。

所以,可以以每一条边作为一个点,把左边界的边和下边界的边作为起点,右边界和上边界作为终点,求出最短路即是答案。

接下来就是连边的问题,如果i和j之间连边,那么从i连向j,那么这条边的权值就是i边的权值(这时候是把边当作点的);若是从j向i连边,那么就是j边的权值作为这条边的权值。

最后是哪些些边之间要连边的问题,处在同一个小三角形当中的边两两之间都要连边。

一开始以为只有对角线要和两条直角边连线,最后画图发现其实两条直角边互相连线也是必须的。

如图:(自己画的,很丑)

这题用到了超级源点的技巧,然后优先队列优化的Dijkstra。

最难的还是如何给边编号的问题,我所用的编号就是题目的输入顺序,水平边和竖直边以及对角线的编号之间存在着一定的关系,可以推导得出,只不过比较繁琐,所以代码略长。

代码:

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <algorithm>
  4 #include <vector>
  5 #include <queue>
  6 using namespace std;
  7 
  8 const int N = 5e6;
  9 const int inf = 0x3f3f3f3f;
 10 
 11 typedef pair<int,int> pii;
 12 
 13 int d[N];
 14 int w[N];
 15 
 16 struct edge
 17 {
 18     int to,cost;
 19     edge(){};
 20     edge(int a,int b)
 21     {
 22         to = a;
 23         cost = b;
 24     }
 25 };
 26 
 27 vector<edge> es;
 28 vector<int> g[N];
 29 
 30 void adde(int from,int to,int cost)
 31 {
 32     es.push_back(edge(to,cost));
 33     g[from].push_back(es.size() - 1);
 34 }
 35 
 36 void init(int n)
 37 {
 38     es.clear();
 39     
 40     for (int i = 0;i <= n;i++) g[i].clear();
 41     
 42     memset(d,inf,sizeof(d));
 43 }
 44 
 45 void dij(int n)
 46 {
 47     priority_queue<pii,vector<pii>,greater<pii> > pq;
 48     
 49     d[0] = 0;
 50     
 51     pq.push(pii(0,0));
 52     
 53     while (!pq.empty())
 54     {
 55         pii x = pq.top();pq.pop();
 56         
 57         int v = x.second;
 58         
 59         if (d[v] < x.first) continue;
 60         
 61         for (int i = 0;i < g[v].size();i++)
 62         {
 63             int id = g[v][i];
 64             
 65             edge e = es[id];
 66             
 67             if (d[e.to] > e.cost + d[v])
 68             {
 69                 d[e.to] = d[v] + e.cost;
 70                 pq.push(pii(d[e.to],e.to));
 71             }
 72         } 
 73     }
 74 }
 75 
 76 int main()
 77 {
 78     int n,m;
 79     int kase = 0;
 80     
 81     while (scanf("%d%d",&n,&m) != EOF)
 82     {
 83         if (m == 0 && n == 0) break;
 84         
 85         int cnt = 0;
 86         
 87         //init(n,m);
 88         
 89         for (int i = 0;i < n;i++)
 90         {
 91             for (int j = 0;j < m - 1;j++)
 92             {
 93                 int tmp;
 94                 
 95                 scanf("%d",&tmp);
 96                 
 97                 w[++cnt] = tmp;
 98             }
 99         }
100         
101         for (int i = 0;i < n - 1;i++)
102         {
103             for (int j = 0;j < m;j++)
104             {
105                 int tmp;
106                 scanf("%d",&tmp);
107                 w[++cnt] = tmp;
108             }
109         }
110         
111         for (int i = 0;i < n - 1;i++)
112         {
113             for (int j = 0;j < m - 1;j++)
114             {
115                 int tmp;
116                 scanf("%d",&tmp);
117                 w[++cnt] = tmp;
118             }
119         }
120         
121         int rs = 1,cs = n * (m - 1) + 1,ds = n * (m - 1) + m * (n - 1) + 1;
122         
123         //int sume = n * (m - 1) + m * (n - 1) + (m - 1) * (n - 1);
124         
125         init(cnt);
126         
127         for (int i = ds;i <= cnt;i++)
128         {
129             int num = (i - ds) / (m - 1);
130             int curds = ds + (m - 1) * num;
131             int curcs = cs + num * m;
132             int currs = rs + num * (m - 1);
133             int tmp = i - curds;
134             int curc = curcs + tmp,curr = currs + tmp;
135             
136             adde(curc,i,w[curc]);
137             adde(i,curc,w[i]);
138             adde(i,curc + 1,w[i]);
139             adde(curc+1,i,w[curc+1]);
140             adde(i,curr,w[i]);
141             adde(curr,i,w[curr]);
142             adde(curr + m - 1,i,w[curr + m - 1]);
143             adde(i,curr + m - 1,w[i]);
144             adde(curc,curr+m-1,w[curc]);
145             adde(curr + m - 1,curc,w[curr + m - 1]);
146             adde(curr,curc + 1,w[curr]);
147             adde(curc+1,curr,w[curc+1]);
148         }
149         
150         for (int i = 0;i < n - 1;i++)
151         {
152             adde(0,cs + i * m,0);
153         }
154         
155         for (int i = 0;i < m - 1;i++)
156         {
157             adde(0,(n - 1) * (m - 1) + 1 + i,0);
158         }
159         
160         dij(cnt);
161         
162         int ans = inf;
163         
164         for (int i = 1;i <= m - 1;i++)
165         {
166             ans = min(ans,d[i] + w[i]);
167         }
168         
169         for (int i = 1;i <= n - 1;i++)
170         {
171             int v = n * (m - 1) + m * i;
172             ans = min(ans,d[v] + w[v]);
173         }
174         
175         printf("Case %d: Minimum = %d
",++kase,ans);
176     }
177     
178     return 0;
179 }
原文地址:https://www.cnblogs.com/kickit/p/8809255.html