又来喽
嗯,昨天给自己放了一天假哈,所以也就没啥好些的了。
今天呢,上午刷了一题,外加写了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;
}
晚上的话,那些大神们讲了博弈论、树状数组云云。。。
不懂,也就不吐糟了。