hdu2962trucking

这道题难在要在一定条件下求得最短路。对车载高度进行二分,求出较高车载高度的情况下的最短路。通过判断是否能形成最短路来不断调整车载高度,如果在该车载高度情况下不能形成最短路则调低车载高度,否则调高车载高度。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
const int Max=1200;
const int INF=1e9;
int n,m,star,endd;
int d[Max],Map[Max][Max],height[Max][Max];      //Map用来存放路长,height存放路限高
bool vis[Max];                                  //vis标记该点是否已经访问过
void init()
{
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++)
        {
            Map[i][j]=INF;                      //将任意两点间路长初始化无穷
            height[i][j]=0;                     //路限高初始化为0
        }
}
bool dijstra(int lim)
{
    memset(vis,0,sizeof(vis));                  //将所有点都初始化为未访问过
    for(int j=1; j<=n; j++)
    {
        if(lim<=height[star][j])                //将与起点连通且该路限高大于车高的路更新
        {
            d[j]=Map[star][j];
        }
        else
        {
            d[j]=INF;                           //其余的路设为不通
        }
    }
    vis[star]=1;                                //标记经过该点
    for(int k=0; k<n; k++)                      //循环n次
    {
        int x=0,mm=INF;                         //将x设为不可能更新到的值,用来判断是否有与起点连通的路
        for(int i=1; i<=n; i++)
        {
            //不可以是<=mm,如果有等号,则如果没有与源点的通路,就会一直更新到n,影响判断x,如果终点为n,则会一直逼近车载限高
            if(!vis[i]&&d[i]<mm)               //找出未访问过的点到源点最小的节点x
            {
                mm=d[x=i];
            }
        }
        if(x==0)                               //说明起止点间没通路,需调低车载高度
            return false;
        else if(x==endd)                       //说明找到最短路,需调高车载高度
            return true;
        vis[x]=1;
        for(int i=1; i<=n; i++)
        {
            if(!vis[i]&&height[x][i]>=lim)     //如果x到未访问的点之间路的限高大于车载高度
            {
                d[i]=min(d[i],d[x]+Map[x][i]); //更新源点到未访问的点的路径长度
            }
        }
    }
}
int main()
{
    int t=0;
    while(scanf("%d%d",&n,&m)!=EOF&&(n+m)!=0)
    {
        init();
        int aa,bb,cc,dd;
        for(int i=1; i<=m; i++)
        {
            scanf("%d%d%d%d",&aa,&bb,&cc,&dd);
            if(cc==-1)
                cc=INF;
            Map[aa][bb]=Map[bb][aa]=dd;             //双边处理
            height[aa][bb]=height[bb][aa]=cc;
        }
        int limit,mid,left,right,ans;
        scanf("%d%d%d",&star,&endd,&limit);         //起点终点和车载的限高
        left=1,right=limit,ans=INF;
        while(left<=right)                          //跳出循环时的right即为最优车载高度
        {
            mid=(left+right)/2;                     //对车载高度二分,求出能达到最高车载高度
            if(dijstra(mid))                        //如果返回true,说明有起止点间的最短路
            {
                left=mid+1;                         //提高车载高度
                ans=d[endd];                        //记录路径长度
            }
            else
            {
                right=mid-1;                        //降低车载高度
            }
        }
        if(t)
            printf("\n");
        printf("Case %d:\n",++t);
        if(ans==INF)                                //ans值最终没变说明起止点不通
            printf("cannot reach destination\n");
        else
        {
            printf("maximum height = %d\n",right);
            printf("length of shortest route = %d\n",ans);
        }
    }
    return 0;
}

下面这个是用SPFA做的跟dijkstra的处理方法基本类似。

#include<stdio.h>
#include<iostream>
#include<queue>
#include<string.h>
#include<algorithm>
using namespace std;
const int MAX=999999999;
const int edge_max=21000;       //边的最大值
const int point_max=1110;        //点的最大值
struct node
{
    int en;
    int height;
    int lenth;
    int next;
} edge[edge_max];
int pos_in_edge[point_max];            //在边中的位置
int dis[point_max],n,m,Star,End,limit;
bool vis[point_max];
queue<int>Q;
void init()
{
    memset(pos_in_edge,-1,sizeof(pos_in_edge));     //初始化表头
    int positn=1,sta,enb,lenc,heid;
    for(int i=0; i<m; i++)
    {
        cin>>sta>>enb>>heid>>lenc;
        if(heid==-1)
            heid=MAX;
        edge[positn].en=enb;
        edge[positn].lenth=lenc;
        edge[positn].height=heid;
        edge[positn].next=pos_in_edge[sta];
        pos_in_edge[sta]=positn++;
        swap(sta,enb);                          //做双边处理
        edge[positn].en=enb;
        edge[positn].lenth=lenc;
        edge[positn].height=heid;
        edge[positn].next=pos_in_edge[sta];
        pos_in_edge[sta]=positn++;
    }
    cin>>Star>>End>>limit;
}
void SPFA(int lim)
{
    memset(vis,0,sizeof(vis));
    fill(dis,dis+point_max,MAX);                //dis数组初始化为最大
    dis[Star]=0;                                //处理源点
    vis[Star]=true;
    Q.push(Star);
    while(!Q.empty())
    {
        int e_st_p=Q.front();                  //边的起点
        vis[e_st_p]=false;
        Q.pop();
        for(int j=pos_in_edge[e_st_p]; j!=-1; j=edge[j].next)
        {
            if(edge[j].height<lim)
                continue;
            int e_en_p=edge[j].en;            //边的终点
            if(dis[e_en_p]>edge[j].lenth+dis[e_st_p])   //松弛操作
            {
                dis[e_en_p]=edge[j].lenth+dis[e_st_p];
                if(!vis[e_en_p])
                {
                    Q.push(e_en_p);
                    vis[e_en_p]=true;
                }
            }
        }
    }

}
int main()
{
    int t=0;
    while(scanf("%d%d",&n,&m)!=EOF&&(n+m)!=0)
    {
        init();
        int left=1,right=limit,ans=MAX,mid;
        while(left<=right)
        {
            mid=(left+right)/2;
            SPFA(mid);
            if(dis[End]!=MAX)
            {
                left=mid+1;
                ans=dis[End];
            }
            else
            {
                right=mid-1;
            }
        }
        if(t)
            printf("\n");
        printf("Case %d:\n",++t);
        if(ans==MAX)
            printf("cannot reach destination\n");
        else
        {
            printf("maximum height = %d\n",right);
            printf("length of shortest route = %d\n",ans);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值