hdu2433之最短路

来源:互联网 发布:铜排折弯算法 编辑:程序博客网 时间:2024/05/18 17:58

这题写了我好久。。大哭

Travel

Time Limit: 10000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1276    Accepted Submission(s): 436


Problem Description
      One day, Tom traveled to a country named BGM. BGM is a small country, but there are N (N <= 100) towns in it. Each town products one kind of food, the food will be transported to all the towns. In addition, the trucks will always take the shortest way. There are M (M <= 3000) two-way roads connecting the towns, and the length of the road is 1.
      Let SUM be the total distance of the shortest paths between all pairs of the towns. Please write a program to calculate the new SUM after one of the M roads is destroyed.

 

Input
      The input contains several test cases.
      The first line contains two positive integers N, M. The following M lines each contains two integers u, v, meaning there is a two-way road between town u and v. The roads are numbered from 1 to M according to the order of the input.
      The input will be terminated by EOF.

 

Output
      Output M lines, the i-th line is the new SUM after the i-th road is destroyed. If the towns are not connected after the i-th road is destroyed, please output “INF” in the i-th line. 
 

Sample Input
5 45 11 33 25 42 21 21 2
 

Sample Output
INFINFINFINF22

题目是要求每次删除地i条边后以1,2,3,...n为起始点到其他点的最短路和的总和


分析:从题意可以想到用spfa,毕竟spfa是求单源多点的最短路的好算法,所以可以想到每次删除第i条边时,我们只需要暂时把这条边长度赋值无穷大,然后对1,2,3,....n各点进行spfa然后求和,这是最初的思想,但是看复杂度m*n*m=9*10^8肯定会超时,第一个m代表删除m条边,第二个n表示每次删除一条边后就对1,2,3....n个点进行spfa,第三个m表示spfa的复杂度(由于边长度为1所以每个点其实只要入队一次,所以复杂度是m),在m*n*m中我们能优化的只能是第一个m了,根据上面n表示的意思我们知道每起始个点都要因为m条边而进行spfa m次,但是其实以起始点i开始的最短路边只有n-1,条,也就是说有m-n+1条边与以起始点i开始的最短路无关(即影响不到),那么如何去判断什么时候进行spfa呢??在这里引进一个数组flag[i][u][v]表示以点i作为起始点的最短路是否含有边u-v,所以我们要预先进行spfa来标记flag

这样就能根据flag[i][u[v]]来决定什么时候进行spfa,所以复杂度就变成了n*n*m,第一个n表示每个点最多要进行n-1(o(n))次spfa


邻接表的L

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<string>#include<queue>#include<algorithm>#include<map>#include<iomanip>#define INF 99999999using namespace std;const int MAX=100+10;int dist[MAX],edgenum[MAX][MAX];bool mark[MAX],flag[MAX][MAX][MAX];int size,head[MAX],n,m,pos[3002],sum[MAX];struct Edge{int v,w,next;Edge(){}Edge(int V,int W,int Next):v(V),w(W),next(Next){}}edge[3002*2];inline void Init(int num){memset(head,-1,sizeof(int)*(num+2));memset(edgenum,0,sizeof edgenum);memset(flag,false,sizeof flag);size=0;} inline void InsertEdge(int u,int v,int w){edge[size]=Edge(v,w,head[u]);head[u]=size++;}int spfa(int s,bool p){int ans=0;queue<int>enqueue;for(int i=1;i<=n;++i)dist[i]=INF,mark[i]=false;dist[s]=0;mark[s]=true;enqueue.push(s);while(!enqueue.empty()){int u=enqueue.front();enqueue.pop();mark[u]=false;for(int i=head[u];i != -1;i=edge[i].next){int v=edge[i].v;if(dist[v]>dist[u]+edge[i].w){dist[v]=dist[u]+edge[i].w;if(!mark[v]){if(p)flag[s][u][v]=flag[s][v][u]=true;enqueue.push(v);mark[v]=true;}}}}for(int i=1;i<=n;++i){if(dist[i] == INF)return INF;else ans+=dist[i];}return ans;}int main(){int ans,u,v,temp;while(cin>>n>>m){Init(n);for(int i=0;i<m;++i){cin>>u>>v;pos[i]=size;//pos用来确定第i条边的位置 InsertEdge(u,v,1);InsertEdge(v,u,1);++edgenum[u][v];++edgenum[v][u];}ans=temp=0;for(int i=1;i<=n;++i){sum[i]=spfa(i,1);if(sum[i] == INF){ans=INF;break;}else ans+=sum[i];}for(int i=0;i<m;++i){u=edge[pos[i]+1].v;v=edge[pos[i]].v;int s=ans;if(ans == INF)cout<<"INF"<<endl;else if(edgenum[u][v]-1>0)cout<<ans<<endl;else{edge[pos[i]+1].w=INF;//edge[u][v]=INFedge[pos[i]].w=INF;//edge[v][u]=INF;for(int j=1;j<=n;++j){if(flag[j][u][v]){temp=spfa(j,0);if(temp == INF){cout<<"INF"<<endl;break;}else s+=temp-sum[j]; }}if(temp != INF)cout<<s<<endl;edge[pos[i]+1].w=1;edge[pos[i]].w=1;}}}return 0;}/*5 51 22 33 55 44 1*/
非邻接表的:

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<string>#include<queue>#include<algorithm>#include<map>#include<iomanip>#define INF 99999999using namespace std;const int MAX=100+10;int edgenum[MAX][MAX],s[3002][2];//edgenum表示边u-v的数量,s是输入的边 bool edge[MAX][MAX],flag[MAX][MAX][MAX],mark[MAX];//flag标记起点为i的最短路包含u-v边int n,m,sum[MAX],dist[MAX];//sum是预定义得到的以i为起始点的最短路和,dist是点i到起始点的距离 void Init(){memset(edgenum,0,sizeof edgenum);memset(flag,false,sizeof flag);memset(edge,false,sizeof edge);}int spfa(int s,bool p){int ans=0,u;for(int i=1;i<=n;++i)dist[i]=INF,mark[i]=false;dist[s]=0;mark[s]=true;queue<int>enqueue;enqueue.push(s);while(!enqueue.empty()){u=enqueue.front();enqueue.pop();mark[u]=false;for(int v=1;v<=n;++v){if(edge[u][v] && dist[v]>dist[u]+1){//dist[v]>dist[u]+edge[u][v]dist[v]=dist[u]+1;if(!mark[v]){mark[v]=true;enqueue.push(v);if(p)flag[s][u][v]=flag[s][v][u]=true;}}}}for(int i=1;i<=n;++i){if(dist[i] == INF){ans=INF;break;}else ans+=dist[i];}return ans;}int main(){int u,v,ans,temp;while(cin>>n>>m){Init();for(int i=0;i<m;++i){cin>>u>>v;edge[u][v]=edge[v][u]=true;++edgenum[u][v];++edgenum[v][u];s[i][0]=u,s[i][1]=v;}ans=temp=0;for(int i=1;i<=n;++i){//预处理好以点i为起始点的最短路和 sum[i]=spfa(i,true);//第二个参数是判断spfa里要不要执行flagif(sum[i] == INF){ans=INF;break;}else ans+=sum[i];}for(int i=0;i<m;++i){u=s[i][0];v=s[i][1];int num=ans;if(ans == INF)cout<<"INF"<<endl;else if(edgenum[u][v]-1>0)cout<<ans<<endl;else{edge[u][v]=edge[v][u]=false;for(int j=1;j<=n;++j){if(flag[j][u][v]){temp=spfa(j,false);if(temp == INF)break;else num+=temp-sum[j];}}if(temp == INF)cout<<"INF"<<endl;else cout<<num<<endl;edge[u][v]=edge[v][u]=true;}}}return 0;} 


原创粉丝点击