代码长度限制 16 KB
时间限制 1000 ms
内存限制 64 MB
题目描述
总所周知,联通的路由之间经常会出现故障。keven正在峡谷之巅快乐,无空维护路由之间的最短路,那么请你帮他回答所有的询问。
首先给出一个网络,现简化为无向连通图,有 n 个路由, m 条边组成,且每条边长均为1。
会出现3种如下操作:
操作1:A,B 两个路由间的通路断开。
操作2:A,B 两个路由间的通路连接。
操作3:询问 A,B 间的最短路。
输入格式
第一行三个整数 n,m,q(1<=n<=100,1<=m<=n∗(n−1)/2,1<q<=10000)
接下来 m 行,每行 A,B 两个整数表示 A,B 间有一条通路
接下来 q 行,每行 op,A,B 三个整数,对应上述操作
保证所有输入合法,不出现重边、自环。
输出格式
您需要按顺序回答每次操作3,如果联通输出最短路的大小,否则输出-1
输入样例
3 3 8
3 2
1 2
3 1
3 2 3
3 1 3
1 2 3
3 3 2
3 2 1
1 1 3
2 2 3
3 1 3
输出样例
1
1
2
1
2
个人思路
- 可以看出是无向图的最短路径问题,常用算法就是Dijkstr和folyd,用folyd的3个for循环加上指令输入的一个循环,时间复杂度过大
- 尝试了用dfs依然时间超限,也在意料之中
- 所以这里只能考虑迪杰斯特拉算法,进一步说明见代码注释
#include<bits/stdc++.h>
using namespace std;
#define MAX 0x3f3f3f
int n,m,q;
int ans[110][110];//存储无向图
int disk[110];//标记最短路径
bool marked[110];//标记某一个点是否已被确定为最小路径
void Disk(int r)//迪杰斯特拉算法,r这里表示起止位置
{
for(int i=1;i<=n;i++)
{
disk[i]=ans[r][i];//利用图初始化最短路径
marked[i]=false;//将所有点都初始化为未被标记
}
marked[r]=true;//标记当前起始位置
for(int i=1;i<=n;i++)//保证所有的点能被访问到的点都能被访问到
{
int index=0;//初始化下标和最小值
int min=MAX;
for(int j=1;j<=n;j++)//找到r到(1-n)之间没被标记过的最小的那个点
{
if(!marked[j]&&disk[j]<min)
{
index=j;//不断更新最小的路径值和下标
min=disk[j];
}
}
if(index!=0)//可以找到最小路径则标记被找到的点已访问
{
marked[index]=true;
}
//对刚标记的下标为index的点进行可访问点遍历
for(int j=1;j<=n;j++)
{
//更新下标为index的点可访问点的最短路径
if(!marked[j]&&disk[j]>min+ans[index][j])
{
disk[j]=min+ans[index][j];
}
}
}
}
int main()
{
cin>>n>>m>>q;
for(int i=0;i<=n;i++)//初始化,自身到自身值为0
{
disk[i]=MAX;
marked[i]=false;
for(int j=0;j<=n;j++)
{
if(i==j)
ans[i][j]=0;
else
ans[i][j]=MAX;
}
}
while(m--)
{
int t,r;//根据输入建图
cin>>t>>r;
ans[t][r]=1;
ans[r][t]=1;
}
while(q--)
{
int cmd,r,t;//指令输入,操作r到t
cin>>cmd>>r>>t;
if(cmd==3)
{
//对起始点r用迪杰斯特拉算法找到最r到其他点的最短路径
Disk(r);
if(disk[t]>=MAX)
{
cout<<"-1"<<endl;
}
else
{
cout<<disk[t]<<endl;
}
}
else if(cmd==1)
{
ans[r][t]=MAX;
ans[t][r]=MAX;
}
else if(cmd==2)
{
ans[t][r]=1;
ans[r][t]=1;
}
}
}