bzoj 1001

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<functional>
#include<queue>
using namespace std;
typedef pair<int, int>p;
struct edgee
{
 int to;
 int value;
}edge[6000020];
int num[1020][1020][2],edgetot,first[2000020],nextt[6000020];
void addedge(int a, int b,int value)
{
 edge[edgetot].to = b;
 edge[edgetot].value = value;
 nextt[edgetot] = first[a];
 first[a] = edgetot;
 edgetot++;
 edge[edgetot].to = a;
 edge[edgetot].value = value;
 nextt[edgetot] = first[b];
 first[b] = edgetot;
 edgetot++;
}
struct com
{
 bool operator()(p a, p b)
 {
  if (a.first == b.first)
   return false;
  return a.first >b.first;
 }
};
priority_queue < p, vector<p>, com > que;
int d[2000020],m,n;
int distra(int s)
{
 d[0] = 0; d[2 * (n - 1)*(m - 1)+1] = 1000000000;
 for (int i = 1; i <n;i++)
 for (int j = 1; j < m;j++)
 for (int k = 0; k < 2; k++)
 {
   d[num[i][j][k]] = 1000000000;
 }
 que.push(p(0, 0));
 while (!que.empty())
 {
  p c = que.top();
  que.pop();
  if (c.first > d[c.second])
   continue;
  for (int i = first[c.second]; i != -1; i = nextt[i])
  {
   int to = edge[i].to;
    if (d[to]>d[c.second] + edge[i].value)
   {
    d[to] = d[c.second] + edge[i].value;
    que.push(p(d[to], to));
   }
  }
 }
 return d[2 * (n - 1)*(m - 1)+1];//在这就返回终点值
}
int diantot=1;
int main()
{
 scanf("%d%d", &n, &m);
 if (n == 1 || m == 1)//这是特判条件
 {
  int a, j=1000000000;
  if (n < m)swap(n, m);
  for (int i = 1; i < n; i++)
  {
   scanf("%d", &a);
   if (a < j)j = a;
  }
  if (j != 1000000000)
   printf("%d\n", j);
  else
   printf("0\n");
  exit(0);
 }

 for (int j = 0; j <= m; j++)//预先给每个点一个编号,虽然这样会搞得常数很大不过好算啊。。。。能过就行。
 {                                     //第i行j列的格子包含2个子节点 右上的是num[i][j][0],左下的是num[i][j][1];
  num[0][j][0]=num[0][j][1] = 0;
  num[n][j][0] = num[n][j][1] = 2 * (n - 1)*(m - 1) + 1;
 }
 for (int i = 1; i < n;i++)
 for (int j = 1; j < m; j++)
 {
   num[i][j][0] = diantot++;
   num[i][j][1] = diantot++;
 }

 for (int i = 0; i <= 2 * (n - 1)*(m - 1) + 1; i++)//记得初始化头结点在遍历边的时候等于-1就停止了,如果边有1 2 3 4 那么加边时就是 -1 加1边 1 -1 加2边 2 1 -1 加3边 3 2 1 -1.。。
 {
  first[i] = -1;
 }

 for (int i = 1; i <= n; i++)//建横向边
 for (int j = 1; j < m; j++)
 {
  int a;
  scanf("%d", &a);
  addedge(num[i][j][0], num[i - 1][j][1], a);
 }
//纵向边
 for (int i = 1; i < n; i++)
 {
  int a1;
  scanf("%d", &a1);
  addedge(num[i][1][1], 2 * (n - 1)*(m - 1) + 1, a1);
  for (int j = 2; j < m; j++)
  {
   int a2;
   scanf("%d", &a2);
   addedge(num[i][j][1], num[i][j-1][0], a2);
  }
  int a3;
  scanf("%d", &a3);
  addedge(num[i][m - 1][0], 0, a3);
 }
//斜的边
 for (int i = 1; i < n;i++)
 for (int j = 1; j < m; j++)
 {
  int a3;
  scanf("%d", &a3);
  addedge(num[i][j][0], num[i][j][1], a3);
 }
//一下是调试代码。。调试技巧:
//1. 看图建没建好你阔以让每条边的值不同这样输出时就会知道边在哪里了 2.注意使用pair时 分清first 与second 的意义3.最后一个点事2*(n-1)*(m-1)+1不是2*(n-1)*(m-1)
 /*for (int i = 1; i < n;i++)
 for (int j = 1; j < m; j++)
 {
  cout << "i:" << i << " " << "j:" << j << " " << "num0:" << num[i][j][0] << endl;
  cout << "i:" << i << " " << "j:" << j << " " << "num1:" << num[i][j][1] << endl;
 }
 for (int i = 0; i < 2 * (n - 1)*(m - 1) + 2; i++)
 {
  cout << "begin: " << i << " ";
  for (int j = first[i]; j != -1; j = nextt[j])
  {
   cout << "边value:"<<edge[j].value<<" "<<"边to:"<<edge[j].to << " ";
  }
  cout << endl;
 }*/
 printf("%d\n",distra(0));
}

此题就是一个最短路。。每次都是从外面到外面的切割发现所以就是相当于不管条件怎么变起点和终点都不会变那么我们阔以考虑最短路(当然只是考虑用,能不能用看情况,这题刚好阔以)。。。

这是个讲的不错的大神。。如有疑问可参考一下

http://blog.csdn.net/nikelong0/article/details/50727840

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值