29/7/2012 ICPC培训 第十四天

又来喽大笑

嗯,昨天给自己放了一天假哈,所以也就没啥好些的了。

今天呢,上午刷了一题,外加写了SPFA算法的代码实现,包括打印最短路径。下午呢,

刷了一题。并且,这两题都是SPFA求解最短路径相关的。晚上,就是大神来上课了,

不过几乎听不懂的说,所以也就没听了。。。尴尬

 

第一题(HDU1385),也就是上次做了一天没A的。

最后在建图的时候采用了反向建图,莫名奇妙就A了。为什么反向建图,我也没搞懂。

#include<iostream>
#include<vector>
#include<queue>
#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 source[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[j][i]);
        }
    }
    
    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(source[end]!=0)
     {  
          printf("-->%d",source[end]); 
          end=source[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();
            source[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)
                {
                    source[to]=now;    //记录下to的来源为now 
                     
                    minPath[to]=cost;
                     
                    if(!inQ[to])
                    {
                        inQ[to]=true;
                        myQ.push(to);
                    }
                }
                else if(minPath[to]==cost)
                {
                    if(now<source[to])
                    {
                        source[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;
}


第二题(HDU1595)

这题如果暴力枚举每一条路径就会超时的。

可以这样来设计算法:

记录下一条最短路径,依次破坏最短路径上的一条路。SPFA求解此时的最短路径。取最大的。

为什么这样设计算法是正确的?

1、如果破坏的而不是最短路径上的路,求解最短路径的值时得到的任是此前的最短路径。也就是说

破坏不是最短路径上的路毫无意义。

2、如果最短路径有多条。

①如果各个最短路径毫不相关,出起点、终点外没有相关的点和边。破坏任意最短路径上的路,SPFA

时都会得到其他最短路径的值。各个最短路径价值一样,取一条破坏即可。

②如果各个最短路径间有相关部分,也有不相关部分。取不想管部分破坏原理同①一样;取相关部分破坏

不论取那条最短路径都是一样的。

3、从以上的分析可以看出,只要首先找到一条最短路径,然后依次破坏其中的一条路,求解当下

最短路径,取其中最大值即可。

代码:

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

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

struct edge
{
    int to;
    int cost;
};
 
int numNode,numEdge;
bool inQ[maxn];
int source[maxn],anotherSource[maxn];
int minPath[maxn];
vector<edge>  myV[maxn]; 
 
void input()
{
    for(int j=0;j<maxn;j++)  //清空 
    {
        myV[j].clear();
    }
    
    int from,to,cost; 
    for(int i=0;i<numEdge;i++)
    {
        scanf("%d%d%d",&from,&to,&cost);
        
        edge e;
        e.cost=cost;
        
        e.to=to;
        myV[from].push_back(e);
        
        e.to=from;
        myV[to].push_back(e); 
    }
}

void SPFA()
{
    memset(inQ,false,sizeof(inQ));
    inQ[1]=true;
    for(int i=0;i<=numNode;i++) minPath[i]=INF;
    minPath[1]=0;
    memset(source,-1,sizeof(source)); 
    
    queue<int> myQ;
    myQ.push(1);
    
    int now,to,cost;
    while(!myQ.empty())
    {
        now=myQ.front();
        myQ.pop();
        inQ[now]=false; 
        
        for(int j=0;j<myV[now].size();j++)
        {
            to=myV[now][j].to;
            cost=minPath[now]+myV[now][j].cost; 
             
            if(minPath[to]>cost)
            {
                minPath[to]=cost;
                
                source[to]=now;
                
                if(!inQ[to])
                {
                    inQ[to]=true;
                    myQ.push(to);
                }  
            }     
         }
     }
     //printf("%d\n",minPath[numNode]); 
}

void getMinPath()
{
    int from=anotherSource[numNode],to=numNode,minCost=-1,temp,i,j;
    bool flag=false;   //加flag保证起点为1的路也会被处理 
    while(from!=1 || !flag)
    {
        if(from==1) flag=true;
         
        for(i=0;i<myV[from].size();i++)
        {
            if(myV[from][i].to==to)
            {
                temp=myV[from][i].cost; 
                myV[from][i].cost=INF;
                break; 
            }
        }
        for(j=0;j<myV[to].size();j++)
        {
            if(myV[to][j].to==from)
            {
                myV[to][j].cost=INF;
                break;
            }
        } 
        
        SPFA();
        
        if(minPath[numNode]!=INF) minCost=minCost>minPath[numNode]?minCost:minPath[numNode];
        
        myV[from][i].cost=myV[to][j].cost=temp; 
        to=from;
        from=anotherSource[from]; 
    }
    
    printf("%d\n",minCost);
}            

void keepSource()   //getMinPath()不能用source[]直接找最短路径 
{
    for(int i=0;i<maxn;i++)
    {
        anotherSource[i]=source[i];
        anotherSource[1]=1; 
    }
}
     
int main()
{  
    while(scanf("%d%d",&numNode,&numEdge)!=EOF)
    {
        input();
        
        SPFA();
        
        keepSource(); 
        
        getMinPath(); 
    }
    
    system("pause");
    return 0;
} 


 

晚上的话,那些大神们讲了博弈论、树状数组云云。。。

不懂,也就不吐糟了。

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值