27/7/2012 ICPC培训 第十二天

眨眼培训就过了大半喽奋斗。我还是很喜欢的。。。

上午做了HDU2112

还是求最短路径的,不同的是这题没有直接给地点标号,需要我们来处理。

这题要注意一下集中情况:

1、start、end地点在下面的路径中不一点会出现,所以在标号时需要对这两个点也处理。

2、无向图的处理可能会增加时间复杂度,但不会改变最短路径的长度,因为除非是负权边,

否则a->b被处理过,b->a一点不会被处理了。

3、这题的建图。利用temp[][]表将地点不重复地存储起来,建立地点和数字标号间的唯一对应

关系。然后在查找建图。

4、SPFA算法,不仅仅可以求出最短路径,还可以判断两点是否连通。(有向图、无向图均可)

代码:

#include<iostream>
#include<vector>
#include<queue> 
using namespace std;

const int maxRoad=10001;  //路径数 
const int maxSize=151;    //地点数 
const int maxLen=31;      //地点的最大长度 
const int INF=0x7fffffff;

struct node   //边 
{
    char start[maxLen];
    char end[maxLen];
    int from;
    int to;
    int cost;
}edge[maxRoad];
 
int minPath[maxSize];   //最短路 
bool inQ[maxSize];       //是否在队列中 
int numEdge,numAdress,from,to;  //路径数、点数、起点、终点 
char start[maxLen],end[maxLen];
char temp[maxSize][maxLen];    //不重复存放地存放每个点 
vector<node> myV[maxSize];     //连接表 

int findIndex(char c[])   //找地点的标示 
{
    for(int i=0;i<numAdress;i++)
    {
        if(strcmp(c,temp[i])==0)
        {
            return i;
        }
    }
    
    return -1;
} 
     
void input()
{
    numAdress=0;
    getchar(); 
    scanf("%s%s",&start,&end);
    
    //如果不在temp[][]表中就放进去 
    if(findIndex(start)==-1) strcpy(temp[numAdress++],start);
    if(findIndex(end)==-1) strcpy(temp[numAdress++],end); 
    
    for(int i=0;i<numEdge;i++)
    {
        getchar(); 
        scanf("%s%s%d",&edge[i].start,&edge[i].end,&edge[i].cost);
        
        if(findIndex(edge[i].start)==-1)  strcpy(temp[numAdress++],edge[i].start);
        if(findIndex(edge[i].end)==-1) strcpy(temp[numAdress++],edge[i].end);
    }
} 

void buildMap()
{
    for(int j=0;j<maxSize;j++)
    {
        myV[j].clear();
    }
     
    from=findIndex(start);
    to=findIndex(end);
    
    for(int i=0;i<numEdge;i++)
    {
        //建立无向图 
        edge[i].from=findIndex(edge[i].start);
        edge[i].to=findIndex(edge[i].end);  
        myV[edge[i].from].push_back(edge[i]); 
        
        edge[i].to=findIndex(edge[i].start);
        edge[i].from=findIndex(edge[i].end);  
        myV[edge[i].from].push_back(edge[i]);
    }
}        

void SPFA()
{
    for(int i=0;i<maxSize;i++)  minPath[i]=INF;
    minPath[from]=0;
    memset(inQ,false,sizeof(inQ));
    inQ[from]=true; 
    
    queue<int> myQ;
    myQ.push(from);
     
    while(!myQ.empty())
    {
        int from,to,cost;
        from=myQ.front();
        myQ.pop();
        
        for(int j=0;j<myV[from].size();j++)
        {
            to=myV[from][j].to;
            cost=myV[from][j].cost+minPath[from];
            
            if(cost<minPath[to])
            {
                minPath[to]=cost;
                
                if(!inQ[to])
                {
                    inQ[to]=true;
                    myQ.push(to);
                }
            }
        }
        
        inQ[from]=false; 
    }
    
    if(minPath[to]!=INF) printf("%d\n",minPath[to]);
    else printf("-1\n"); 
}    
     
int main()
{
    while(scanf("%d",&numEdge)==1,numEdge!=-1)
    {
        if(numEdge==0)
        {
            getchar(); 
            scanf("%s%s",&start,&end);
            
            if(strcmp(start,end)==0) printf("0\n"); 
            else printf("-1\n");
            
            continue; 
        }
         
        input();
        
        buildMap(); 
        
        SPFA();
    }
    
    system("pause");
    return 0;
} 


然后下午和晚上就一直在做HDU1385了。

可是还没搞定呢。。。鄙视

这题不仅要求解最短路径,还要计算节点处费用。不仅如此,还要把路径打印出来。

更坑爹的是,如果有多条最短路径,只打印按字母表排序最小的。。。

一直WA,各种不解,最不解的是网上有些代码明明不对,依旧A了。。。

(打印最短路径,大家可以到这里看看:SPFA最短路径

就把我的WA代码贴下:

#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
using namespace std;

const int maxn=1001;
const int INF=0x7fffffff;

struct edge
{
    int to;
    int cost;
};

int mat[maxn][maxn];
int waste[maxn];
int sourceFirst[maxn]; 

vector<edge> myV[maxn];  //利用临界表存储图 
int numNode;             //点数
int minPath[maxn];       //最短路
int start,end;           //起点、终点 
bool inQ[maxn];          //是否入队 
     
void inputItial()
{
    int i,j;
    
    for(i=1;i<=numNode;i++)  //输入距离矩阵 
    {
        for(j=1;j<=numNode;j++)
        {
            scanf("%d",&mat[i][j]);
        }
    }
    
    for(i=1;i<=numNode;i++)   //输入中转站的费用 
    {
        scanf("%d",&waste[i]);
    }
    
    for(i=0;i<maxn;i++)  //清空再使用 
    {
        myV[i].clear();
    }
    
    for(i=1;i<=numNode;i++)   //建图 
    {
        for(j=1;j<=numNode;j++)
        {
            if(i==j || mat[i][j]==-1) continue;

            edge e;
            e.cost=mat[i][j]+waste[i];
            e.to=j;
            myV[i].push_back(e);          
        }
    }
}

void output(int start,int end)
{
    printf("From %d to %d :\n",end,start);  
    printf("Path: %d",end); 
    
     while(sourceFirst[end]!=0)
     {  
          printf("-->%d",sourceFirst[end]); 
          end=sourceFirst[end];
     }
     printf("\n");
}          
       
void SPFA(int start,int end)   //最短路径快速算法 Shortest Path Faster Algorithm
{
        memset(inQ,false,sizeof(inQ));
        inQ[start]=true;
        for(int j=0;j<maxn;j++) minPath[j]=INF;
        minPath[start]=0;
        
        queue<int> myQ;
        myQ.push(start);
   
        int now,to,cost;
        while(!myQ.empty())
        {
            now=myQ.front();
            myQ.pop();
            sourceFirst[start]=0;
            
            for(int k=0;k<myV[now].size();k++)
            {
                to=myV[now][k].to;
                cost=myV[now][k].cost+minPath[now];
             
                if(minPath[to]>cost)
                {
                    sourceFirst[to]=now;    //记录下to的来源为now 
                     
                    minPath[to]=cost;
                     
                    if(!inQ[to])
                    {
                        inQ[to]=true;
                        myQ.push(to);
                    }
                }
                else if(minPath[to]==cost)
                {
                    if(now<sourceFirst[to])
                    {
                        sourceFirst[to]=now;
                    }
                } 
            }
            
            inQ[now]=false;
        }
        
        if(start==end)
        {
            printf("From %d to %d : \n",start,end);
            printf("Path: %d\n",start);
            printf("Total cost : 0\n\n");
        }
        else
        {
            output(start,end);
            printf("Total cost : %d\n\n",minPath[end]-waste[start]);
        }
}
         
int main()
{
    while(scanf("%d",&numNode)==1,numNode)
    {
        inputItial();
        
        while(scanf("%d%d",&start,&end)==2,start!=-1&&end!=-1)
        {
            SPFA(end,start);
        }
    }
 
    system("pause");   
    return 0;
}

通过上次的比赛,我觉得做题还是得扎实。

做了一题完全可以给自己加点难度。什么数据范围搞大点、输出格式严格点、

时间放短点。。。

这样可以引导自己更深入的思考问题,个人觉得可能比你一直做模板题,浑浑噩噩的效果

会好点的。这也是我给自己提的要求。所以,我一定要把HDU1385搞定的呀。

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值