关于 最短路条数 和 边不可重复最短路条数问题 /hdu3599(边不可重复最短路)

原先一直在做一道省赛题,由于题意错误理解成球最短路条数,误打误撞敲了最短路条数,又发现hdu3599(多校)求边不可重复最短路条数。下面说说俩种问题解法:

最短路条数:

求一个图一共一几条最短路径,思路:先从终点跑一边最短路,记录终点到到所有点最短距离(d【i】),然后从起点出发,dfs 按d[i]走(必是最短路径),一句话:我到终点的最短路条数=我的所有孩子到终点的最短路条数之和,这样只需一遍即可。这不知道是不是叫记忆化搜索?

边不可重复最短路径条数:(最短路+建新图之最大流)

hdu3599题意:求1-->n最短路条数,所有路径边不可重复。思路:边不可重复??!!转为流量的为1 的话,求最大流啊(以后切记该方法,不可重复问题转最大流)!于是:先跑一遍最短路(随便从起点还是终点),然后按老图中是最短路的边就在新图添加一条边,权为1,这样的话,从起点到终点跑最大流即为答案。

附代码:问题一:

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
int n;
int e[100000][3];int head[2000];
int nume=0;
int d[2000];
const int inf =0x3f3f3f3f;
int vis[2000];
int inq[2000];
void adde(int a,int b,int w)
{
    e[nume][0]=b;e[nume][1]=head[a];head[a]=nume;
    e[nume++][2]=w;
    e[nume][0]=a;e[nume][1]=head[b];head[b]=nume;
    e[nume++][2]=w;
}
void spfa()              //一遍求出终点到所有点的最短路长度d[i]。
{
    queue<int>q;
    int start;
    start=n;
    inq[start]=1;
    q.push(start);
    d[start]=0;
    while(!q.empty())
    {
        int cur=q.front();
       q.pop();
       inq[cur]=0;
       for(int i=head[cur];i!=-1;i=e[i][1])
       {
           int v=e[i][0];
          if(d[cur]+e[i][2]<d[v])
              {
                  d[v]=d[cur]+e[i][2];
                  if(!inq[v])
                  {
                      inq[v]=1;
                      q.push(v);
                  }
              }
       }
    }
    return ;
}
long long counted[2000];    //点i到终点有几条最短路
int nowd[2000];            //从原点出发当前所走的长度
long long dfs(int cur)          //记忆化收索? 访问所有点一遍求出最短路条数,
{
    if(cur==n)
       return 1;
    for(int i=head[cur];i!=-1;i=e[i][1])
       {
           int v=e[i][0];
              if(nowd[cur]+e[i][2]+d[v]!=d[1])   //走这一步必需是最短的
                  continue;
            if(!vis[v])                          //没有走过
            {
              nowd[v]=nowd[cur]+e[i][2];
              vis[v]=1;
              counted[cur]+=dfs(v);            //我所有孩子(是最短路径中)到目标的最短路之和为我到目标最短路
            }
            else
            {
             counted[cur]+=counted[v];    //该孩子最短路条数已经算出
            }
       }
     return counted[cur];
}
int main()
{
    int ta;
    cin>>ta;
    while(ta--)
    {
          scanf("%d",&n);
          int aa,bb,cc;
           for(int i=0;i<=n;i++)
            {
                head[i]=-1;
                nowd[i]=d[i]=inf;
               inq[i]=counted[i]=vis[i]=0;
             }
            nume=0;
       while(~scanf("%d%d%d",&aa,&bb,&cc)&&(aa||bb||cc))
             adde(aa,bb,cc);
         spfa();
        counted[n]=1;
        nowd[1]=0;
        vis[1]=1;
       cout<<dfs(1)<<endl;
    }
    return 0;
}

问题2:

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
int n;
int e[2260000][3];int head[1510];
int nume=0;
int d[1510];
const int inf =0x3f3f3f3f;
int inq[1510];
void adde(int a,int b,int w)   //原图
{
    e[nume][0]=b;e[nume][1]=head[a];head[a]=nume;
    e[nume++][2]=w;
    e[nume][0]=a;e[nume][1]=head[b];head[b]=nume;
    e[nume++][2]=w;
}
int ee[2260000][3];int head2[1510];     //新图
void adde2(int a,int b)
{
    ee[nume][0]=b;ee[nume][1]=head2[a];head2[a]=nume;
    ee[nume++][2]=1;
    ee[nume][0]=a;ee[nume][1]=head2[b];head2[b]=nume;
    ee[nume++][2]=0;
}
void spfa()              //求出终点到所有点的最短路长度d[i]。
{
    queue<int>q;
    int start;
    start=n;
    inq[start]=1;
    q.push(start);
    d[start]=0;
    while(!q.empty())
    {
        int cur=q.front();
       q.pop();
       inq[cur]=0;
       for(int i=head[cur];i!=-1;i=e[i][1])
       {
           int v=e[i][0];
          if(d[cur]+e[i][2]<d[v])
              {
                  d[v]=d[cur]+e[i][2];
                  if(!inq[v])
                  {
                      inq[v]=1;
                      q.push(v);
                  }
              }
       }
    }
    return ;
}
int vis[1510];int lev[1510];
int nowd[1510];                  //从原点出发当前所走的长度
void dfs_getg(int cur)          // 遍历一次老图获得新图
{
    vis[cur]=1;                     //注意这里要标记访问,否则新图有重边!开始因为这个WA了好几遍!
    if(cur==n)
       return ;
    for(int i=head[cur];i!=-1;i=e[i][1])
       {
           int v=e[i][0];
           if(nowd[cur]+e[i][2]+d[v]!=d[1])   //走这一步必需是最短的
                  continue;
            else                          //没有走过
            {
              nowd[v]=nowd[cur]+e[i][2];
              adde2(cur,v);
              if(!vis[v])            //这里在添加边之后方可进入,
              dfs_getg(v);
            }
       }
     return ;
}

bool bfs()                       //dinic不解释
{
    for(int i=0;i<=n;i++)
      vis[i]=lev[i]=0;
    queue<int>q;
    q.push(1);
     vis[1]=1;
    while(!q.empty())
    {
       int cur=q.front();
       q.pop();
       for(int i=head2[cur];i!=-1;i=ee[i][1])
       {
           int v=ee[i][0];
           if(!vis[v]&&ee[i][2]>0)
           {
                lev[v]=lev[cur]+1;
                if(v==n) return 1;
                 vis[v]=1;
                q.push(v);
           }
       }
    }
    return vis[n];
}
int dfs(int u,int minf)
{
    if(u==n||minf==0)return minf;
    int sumf=0,f;
    for(int i=head2[u];i!=-1&&minf;i=ee[i][1])
       {
           int v=ee[i][0];
           if(ee[i][2]>0&&lev[v]==lev[u]+1)
           {
               f=dfs(v,ee[i][2]<minf?ee[i][2]:minf);
               ee[i][2]-=f;ee[i^1][2]+=f;
               minf-=f;sumf+=f;
           }
       }
       return sumf;
}
int dinic()
{
    int sum=0;
    while(bfs())
     sum+=dfs(1,inf);
    return sum;
}
int main()
{
    int ta;
    cin>>ta;
    while(ta--)
    {
          scanf("%d",&n);
          int aa,bb,cc;
           for(int i=0;i<=n;i++)
            {
                head[i]=-1;
                nowd[i]=d[i]=inf;
                inq[i]=vis[i]=0;
            }
            nume=0;
       while(~scanf("%d%d%d",&aa,&bb,&cc)&&(aa||bb||cc))
              adde(aa,bb,cc);
            if(n==1){cout<<0<<endl;  continue;}          // 1个点的时候要特判!!
         spfa();
         nume=0;
       for(int i=0;i<=n;i++)
          head2[i]=-1;
        nowd[1]=0;
        dfs_getg(1);
        cout<<dinic()<<endl;
    }
    return 0;
}

附几组数据:

5

1 2 1

2 3 1

3 5 1

1 3 2

1 4 2

3 4 2

0 0 0

4

1 0 2

2 0 2

1 3 1

2 3 3

2 4 1

1 2 4

0 0 0

6

1 2 1

3 2 1

3 4 1

1 3 2

4 2 2

4 5 1

5 6 1

4 6 2

0 0 0

1

0 0 0

关于 最短路条数 和 边不可重复最短路条数问题 /hdu3599(边不可重复最短路),布布扣,bubuko.com

时间: 2024-10-12 04:25:50

关于 最短路条数 和 边不可重复最短路条数问题 /hdu3599(边不可重复最短路)的相关文章

Openjudge-计算概论(A)-第二个重复出现的数

描述: 给定一个正整数数组(元素的值都大于零),输出数组中第二个重复出现的正整数,如果没有,则输出字符串"NOT EXIST". 输入第一行为整数m,表示有m组数据.其后每组数据分两行:第一行为正整数n(3 < n < 500),表示数组的长度:第二行是n个正整数,正整数间用空格分开.输出有m行输出,每行输出对于数组中第二个重复出现的正整数,如果没有,则输出字符串"NOT EXIST". 样例输入 5 10 1 3 5 7 9 7 8 5 2 6 10

一个数组中有65535个数不重复的大于0的整数(即:0~~65535内所有不重复的整数,数序是杂乱无章的), 用最快的方式排序

备注:如果这个问题你考虑到用元素对比就大错特错了 当然这个算法还不是最优的,不能代表普遍性.但可以引申,总体还是这个思路,无非就是“填空”操作 public class OrderLink { /** * 一个数组中有65535个数不重复的大于0的整数(即:0~~65535内所有不重复的整数,数序是杂乱无章的), * 用最快的方式排序 * @param args */ public static void main(String[] args) { //例如:一个数组中有65535个数不重复的大

MySQL 处理重复数据:防止表中出现重复数据、统计、过滤、删除重复数据

MySQL 处理重复数据 有些 MySQL 数据表中可能存在重复的记录,有些情况我们允许重复数据的存在,但有时候我们也需要删除这些重复的数据. 本章节我们将为大家介绍如何防止数据表出现重复数据及如何删除数据表中的重复数据. 防止表中出现重复数据 你可以在 MySQL 数据表中设置指定的字段为 PRIMARY KEY(主键) 或者 UNIQUE(唯一) 索引来保证数据的唯一性. 让我们尝试一个实例:下表中无索引及主键,所以该表允许出现多条重复记录. CREATE TABLE person_tbl

重复10个1~60顺序且不重复的随机数

$flag = 1; for ($i = 0; $i < 10; $i++) {     $data['mobile'] = $evaluate_mobile;     //随机时间     $second = rand($flag, 6 * ($i + 1));//重复10个1~60顺序且不重复的随机数     $flag = $second + 1;//加1是未免与上一结果重复     $data['second'] = $second;     $result[] = $data; }

12--c完数/最大公约数/最小公倍数/素数/回文数

完数/最大公约数/最小公倍数/素数/回文数 2015-04-08 10:33 296人阅读 评论(0) 收藏 举报  分类: C/C++(60)  哈尔滨工业大学(8)  版权声明:本文为博主原创文章,未经博主允许不得转载. 1.一个正整数的因子是所有可以整除它的正整数.而一个数如果恰好等于除它本身外的因子之和,这个数就称为完数.例如6=1+2+3(6的因子是1,2,3). [cpp] view plain copy #include <stdio.h> #include <math.h

从一列数中筛除尽可能少的数使得从左往右看,这些数是从小到大再从大到小的(网易)。

题目描述: 从一列数中筛除尽可能少的数使得从左往右看,这些数是从小到大再从大到小的(网易). 分析: 这可以用双端LIS方法来解决,先求一遍从左到右的,再求一遍从右到左的.最后从里面选出和最大的即可. 代码实现: #include <iostream> using namespace std; int DoubleEndLIS(int *arr, int len) { int *LIS = new int[len]; int *lefToRight = new int[len]; //left

10-客户端防表单重复提交和服务器端session防表单重复提交

/****************************************************DoFormServlet********************************************************/ package session; import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import

【欧拉函数】(小于或等于n的数中与n互质的数的数目)

[欧拉函数] 在数论,对正整数n,欧拉函数是少于或等于n的数中与n互质的数的数目.此函数以其首名研究者欧拉命名,它又称为Euler's totient function.φ函数.欧拉商数等. 例如φ(8)=4,因为1,3,5,7均和8互质. 从欧拉函数引伸出来在环论方面的事实和拉格朗日定理构成了欧拉定理的证明. [证明]: 设A, B, C是跟m, n, mn互质的数的集,据中国剩余定理,A*B和C可建立一一对应的关系.因此φ(n)的值使用算术基本定理便知, 若 n= ∏p^(α(下标p))p|

MySQL5.5索引数在InnoDB引擎内与索引数在mysql中定义的数量是不一致问题

在查看MySQL错误日志的时候发现这样的错误,如下: 160322 21:42:59 [ERROR] Table baby/baby_order contains 12 indexes inside InnoDB, which is different from the number of indexes 11 defined in the My SQL 大概意思是说表baby_order的索引数在InnoDB引擎内与索引数在mysql中定义的数量是不一致的 为什么会出现这样的错误呢? 参考了这