正文

Zju 2770 Burn the Linked Camp(2)2006-12-11 21:43:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/cruxd/21494.html

分享到:

    正如上文所言,图论的「精髓」就在「转化」了。把一个纯粹的数学问题转换成为可以用图表示的问题,然后通过求解路径(最小值?最大值?),得解。听起来很美。

    以本题为例。给出每个军营的最大容量,给出从军营i到军营j最少的人数,求总人数的最小值。

    这就是典型的差分约束了。有“分”,有“约束”,至于为什么叫“差”,我想大致是因为首先把Ai + .... + Aj写成S[j] - S[i - 1](和之差)的形式吧。btw,这种转换似乎是很常见的处理方法。

    好吧,看上去和图论八竿子搭不上边。以题目给的第一组数据为例。

3 2
1000 2000 1000
1 2 1100
2 3 1300

    我们可以得到如下关系式。(= 省略,下同)

    A1 < 1000, A2 < 2000, A3 < 1000;  

    S2 - S0 > 1100, S3 - S1 > 1300;

    第一组不等式又可写作

    S1 - S0 < 1000, S2 - S1 < 2000, S3 - S2 < 1000

    好吧.....不很明显,再改一下:

    S0 - S1 > -1000, S1 - S2 > -2000, S2 - S3 > -1000

    全部改成>后,回到上文中最后一个结论Distance(v) < Distance(u) + w(u,v)。即D(u) - D(v) > -w(u,v)。 把D改成S,是不是很像?......很牵强吧。

    但毕竟还是有相同的地方。比如离散数学里的传递性:S0 - S1 > -1000, S1 - S2 > -2000, 那么,S0 - S2 > -3000。这就和图的路径奇妙地构成映射了。把每个S看作一个点,从前者向后者引出一条边,以差为负权值(-w(u,v))。这就是图了。

    现在我们就有了一组已知量(5条边)-w(u, v),一组未知量 D0,D1,D2,3个点。这里Di代表的是点i到点3的距离....我的写法总是和标准差那么一点,更规范的写法是到点0的距离。显然,D3为0。这样就转化成了已知边求最短路径(S3-S0)。

    回到问题。现在有五组不等式,要求的是在满足不等式的前提下S3 - S0的最小值。所谓最小值,其实所有满足不等式的D3的最大值;由于边为负,恰巧变成了最短路径。

    当然这只会WA。刘备的兵营没有出现幽灵事件,Ai > 0。而且i到j是有上限的,不能比所有Ai到Aj的和更多。所以刚好是两组对称的不等式。世界是平衡的,不会有绝对的善和恶。

    代码不是很长,大概是Bellman很偷懒的缘故。

 #include <cstdio>
#include <string>

#define mx 9999999

int n, m, a[1001], ei, c[1001], d[1001];

struct Edge
{
 int u, v, w;
} edge[23000];


void init()
{
 ei = 0;
 int i;
 for(i = 0; i <= n; i ++)
  a[i] = mx;
 d[0] = 0;
 a[n] = 0;
}

bool bellman_ford()
{
 int i, k, t;
 for(i = 0; i < n; i ++)
 {  
  for(k = 0; k < ei; k ++)
  {
   t = a[edge[k].u] + edge[k].w;
   if(a[edge[k].u] != mx && t < a[edge[k].v])
   {
    a[edge[k].v] = t;
   }
  }
  //pa();
 }
 for(k = 0; k < ei; k ++)
 {
  if(a[edge[k].u] != mx && a[edge[k].u] + edge[k].w < a[edge[k].v])
  {
   return false;
  }
 }
 return true;
}

int main()
{
 //freopen("in.txt", "r", stdin);
 while(scanf("%d %d", &n, &m) != EOF)
 {
  init();
  int i, u, v, w;
  for(i = 1; i <= n; i ++)
  {
   scanf("%d", &c[i]);
   edge[ei].u = i - 1;   //out
   edge[ei].v = i;    //in
   edge[ei].w = c[i];
   ei ++;
   edge[ei].u = i;
   edge[ei].v = i - 1;
   edge[ei].w = 0;
   ei ++;
   d[i] = c[i] + d[i - 1];
  }
  for(i = 0; i < m; i ++)
  {
   scanf("%d %d %d", &u, &v, &w);
   //f(k) - f(t - 1) >= -j
   edge[ei].u = v;
   edge[ei].v = u - 1;
   edge[ei].w = -w;
   ei ++;
   //f(k) - f(t - 1) <= c[t] + ... + c[k] == (d[k] - d[t - 1])
   edge[ei].u = u - 1;
   edge[ei].v = v;
   edge[ei].w = d[v] - d[u - 1];
   ei ++;
  }
  //pe();
  if(!bellman_ford())
   printf("Bad Estimations\n");
  else
   printf("%d\n", a[n] - a[0]);
 }
 return 0;
}  

阅读(3384) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册