暑假快结束了,唉,不想回学校。
题目的意思很简单,给出一些点和连接这些点的边,如果
1. 无法形成连通图 输出No way:这个用并查集或者DFS检查连通性即可,对本题的数据规模来说时间效率没有什么显著差别,看个人喜好了;e<v-1时,无论如何都无法联通,直接输出No way
2. 能形成连通图,也就有了最小生成树。如果
1.刚好联通,即e==v-1,那么就没有次小生成树,输出 No second way
2.e>v-1,有最小生成树,先用prim算法求最小生成树,然后求次小生成树即可。这里也有本题最大的一个坑点:两点之间可 能有多条路径,所以我们需要把两点间最小的两条路径记录下来。在求次小生成树时,对于在最小生成树中的边,用第二条 路径形成 次小生成树;不在的,用最小的形成次小生成树。
DFS检查连通的版本
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<climits>
using namespace std;
int v, e, closedge[105], tmax[105][105],pre[105],cnt, dis[105][105][2];
bool vis[105], used[105][105];
void dfs(int y)
{
vis[y] = true;
cnt++;
for (int i = 1; i <= v; i++)
if (dis[y][i][0]<INT_MAX && !vis[i])
dfs(i);
}
int smst()
{
memset(vis + 1, 0, sizeof(bool)*v);
for (int i = 1; i <= v; i++)
{
memset(tmax[i] + 1,0, sizeof(int)*v);
memset(used[i] + 1, 0, sizeof(bool)*v);
}
int newv, prev, mincost, ans = 0,sans=INT_MAX;
vis[1] = true;
for (int i = 2; i <= v; i++)
{
closedge[i] = dis[i][1][0];
pre[i] = 1;
}
for (int i = 2; i <= v; i++)
{
mincost = INT_MAX;
for(int j=2;j<=v;j++)
if (!vis[j] && closedge[j] < mincost)
{
newv = j;
prev = pre[j];
mincost = closedge[j];
}
ans += mincost;
vis[newv] = true;
used[newv][prev] = used[prev][newv] = true;
for(int j=1;j<=v;j++)
if (j != newv)
{
if (vis[j]) tmax[j][newv] = tmax[newv][j] = max(tmax[prev][j], mincost);
else if (dis[newv][j][0] < closedge[j])
{
closedge[j] = dis[newv][j][0];
pre[j] = newv;
}
}
}
for(int i=1;i<=v;i++)
for(int j=1;j<i;j++)
if (dis[i][j][0] < INT_MAX)
{
if (used[i][j] && dis[i][j][1] < INT_MAX) sans = min(sans, ans + dis[i][j][1] - dis[i][j][0]);
else if (!used[i][j]) sans = min(sans, ans + dis[i][j][0] - tmax[i][j]);
}
return sans;
}
int main()
{
int T;
scanf("%d", &T);
for (int i = 1; i <= 100; i++) dis[i][i][0] = 0;
//对角线上的始终为0,提前初始化好
for (int w = 1; w <= T; w++)
{
scanf("%d%d", &v, &e);
for (int i = 1; i <= v; i++)
for (int j = 1; j < i; j++)
dis[i][j][0] = dis[j][i][0]=dis[i][j][1]=dis[j][i][1] = INT_MAX;
//INT_MAX表示边不存在
for (int i = 0, u, v, w; i < e; i++)
{
scanf("%d%d%d", &u, &v, &w);
//后两行保证记录的两条边是最小的两条,且第一条小于等于第二条
if (w < dis[u][v][0])
{
dis[u][v][1] = dis[v][u][1] = dis[u][v][0];
dis[u][v][0] = dis[v][u][0] = w;
}
else if (w < dis[u][v][1]) dis[u][v][1] = dis[v][u][1] = w;
}
if (e < v - 1)
{
printf("Case #%d : No way\n", w);
continue;
}
memset(vis + 1, 0, sizeof(bool)*v);
cnt = 0;
dfs(1);
if (cnt < v)
{
printf("Case #%d : No way\n", w);
continue;
}
if (e == v - 1)
{
printf("Case #%d : No second way\n", w);
continue;
}
printf("Case #%d : %d\n",w, smst());
}
return 0;
}
并查集检查联通的版本
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<climits>
using namespace std;
int v, e, closedge[105], tmax[105][105],pre[105],cnt, dis[105][105][2],ufs[105];
bool vis[105], used[105][105];
int find(int y)
{
return ufs[y] < 0 ? y : (ufs[y] = find(ufs[y]));
}
void setUnion(int r1, int r2)
{
cnt--;
if (ufs[r1] < ufs[r2])
{
ufs[r1] += ufs[r2];
ufs[r2] = r1;
}
else
{
ufs[r2] += ufs[r1];
ufs[r1] = r2;
}
}
int smst()
{
memset(vis + 1, 0, sizeof(bool)*v);
for (int i = 1; i <= v; i++)
{
memset(tmax[i] + 1,0, sizeof(int)*v);
memset(used[i] + 1, 0, sizeof(bool)*v);
}
int newv, prev, mincost, ans = 0,sans=INT_MAX;
vis[1] = true;
for (int i = 2; i <= v; i++)
{
closedge[i] = dis[i][1][0];
pre[i] = 1;
}
for (int i = 2; i <= v; i++)
{
mincost = INT_MAX;
for(int j=2;j<=v;j++)
if (!vis[j] && closedge[j] < mincost)
{
newv = j;
prev = pre[j];
mincost = closedge[j];
}
ans += mincost;
vis[newv] = true;
used[newv][prev] = used[prev][newv] = true;
for(int j=1;j<=v;j++)
if (j != newv)
{
if (vis[j]) tmax[j][newv] = tmax[newv][j] = max(tmax[prev][j], mincost);
else if (dis[newv][j][0] < closedge[j])
{
closedge[j] = dis[newv][j][0];
pre[j] = newv;
}
}
}
for(int i=1;i<=v;i++)
for(int j=1;j<i;j++)
if (dis[i][j][0] < INT_MAX)
{
if (used[i][j] && dis[i][j][1] < INT_MAX) sans = min(sans, ans + dis[i][j][1] - dis[i][j][0]);
else if (!used[i][j]) sans = min(sans, ans + dis[i][j][0] - tmax[i][j]);
}
return sans;
}
int main()
{
int T;
scanf("%d", &T);
for (int i = 1; i <= 100; i++) dis[i][i][0] = 0;
for (int w = 1; w <= T; w++)
{
scanf("%d%d", &v, &e);
for (int i = 1; i <= v; i++)
for (int j = 1; j < i; j++)
dis[i][j][0] = dis[j][i][0]=dis[i][j][1]=dis[j][i][1] = INT_MAX;
cnt = v;
memset(ufs + 1, -1, sizeof(int)*v);
for (int i = 0, u, v, w,r1,r2; i < e; i++)
{
scanf("%d%d%d", &u, &v, &w);
r1 = find(u);
r2 = find(v);
if (r1 != r2) setUnion(r1,r2);
if (w < dis[u][v][0])
{
dis[u][v][1] = dis[v][u][1] = dis[u][v][0];
dis[u][v][0] = dis[v][u][0] = w;
}
else if (w < dis[u][v][1]) dis[u][v][1] = dis[v][u][1] = w;
}
if (e < v - 1)
{
printf("Case #%d : No way\n", w);
continue;
}
if (cnt>1)
{
printf("Case #%d : No way\n", w);
continue;
}
if (e == v - 1)
{
printf("Case #%d : No second way\n", w);
continue;
}
printf("Case #%d : %d\n",w, smst());
}
return 0;
}