floyd算法可以解决的问题:
- 最短路
- 传递闭包
- 找最小环
- 恰好经过k条边的最短路(倍增)
//初始化
for(int i = 1; i <= n; i ++ )
for(int j = 1; j <= n; j ++ )
if(i != j) dist[i][j] = inf;
集合:所有从i
出发,最终走到j
,且中间只经过节点编号不超过k
的所有路径
属性:路径长度的最小值
最短路
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#define x first
#define y second
using namespace std;
//floyd求任意两点的最短距离
//求maxd[i], 和i联通且距离最远的点
//情况1:所有maxd[i]的最大值
//情况2:枚举哪两个点连边。i,j满足d[i, j] = inf, maxd[i] + dist[i, j] + maxd[j]
const int N = 160;
int n;
const double inf = 1e20;
double d[N][N], maxd[N];
typedef pair<int, int> PII;
char g[N][N];
PII q[N];
double get_dist(PII a, PII b)
{
double dx = a.x - b.x;
double dy = a.y - b.y;
return sqrt(dx * dx + dy * dy);
}
int main()
{
cin >> n;
for(int i = 0; i < n; i ++ ) cin >> q[i].x >> q[i].y;
for(int i = 0; i < n; i ++ ) cin >> g[i];
for(int i = 0; i < n; i ++ )
for(int j = 0; j < n; j ++ )
{
if(i != j)
if(g[i][j] == '1') d[i][j] = get_dist(q[i], q[j]);
else d[i][j] = inf;
}
for(int k = 0; k < n; k ++ )
for(int i = 0; i < n; i ++ )
for(int j = 0; j < n; j ++ )
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
for(int i = 0; i < n; i ++ )
for(int j = 0; j < n; j ++ )
if(d[i][j] < inf)
maxd[i] = max(maxd[i], d[i][j]);
double res1 = 0;
for(int i = 0; i < n; i ++ ) res1 = max(res1, maxd[i]);//最大半径
double res2 = inf;
for(int i = 0; i < n; i ++ )
for(int j = 0; j < n; j ++ )
if(d[i][j] >= inf)
res2 = min(res2, get_dist(q[i], q[j]) + maxd[i] + maxd[j]);
printf("%.6f", max(res1, res2));
}
传递闭包
两个点可以间接连接,则可以直接相连。
初始化,做一遍Floyd
如果i
能到k
,k
能到j
则i能到j
#include<bits/stdc++.h>
#define intn long long
using namespace std;
queue<pair<int ,int> >q;
vector<int >g[50];
int ind[50];
int indz[50];
int main()
{
int n,m;
char a,t,b;
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>a>>t>>b;
q.push(make_pair(a-'A'+1,b-'A'+1));//存储m组排序序
}
for(int k=1;k<=m;k++)//枚举排序
{
int ind0_num=0;
int flag=1;
pair<int,int> now=q.front();q.pop();
g[now.first].push_back(now.second);//存边
indz[now.second]++;//每次 进行更新入度
queue<int>qq;
for(int i=1;i<=n;i++)
{
ind[i]=indz[i];//使用更新后的入度
if(ind[i]==0)
{
qq.push(i);// 将入度为零的点入队
ind0_num++;//找到入度为零的点的个数,如果多于1,说明有些关系没有确定
}
}
if(ind0_num!=1)
{
flag=0;
}
int cnt=0;
int ans[30];
while(!qq.empty())//拓扑排序
{
int a=qq.front();
qq.pop();
ans[++cnt]=a;//存储答案
ind0_num=0;
for(int i=0;i<g[a].size();i++)
{
ind[g[a][i]]--;//更新入度
if(ind[g[a][i]]==0)
{
qq.push(g[a][i]);//入队
ind0_num++;
}
}
if(ind0_num>1)
{
flag=0;
}
}
if(cnt!=n)//如果cnt!=n,说明有环
{
printf("Inconsistency found after %d relations.",k);
return 0;
}
else
{
if(flag==0)//如果flag=0,说明有点的排序未确定
{
continue;
}
else
{
printf("Sorted sequence determined after %d relations: ",k);
for(int i=1;i<=n;i++)
{
printf("%c",ans[i]+'A'-1);
}
printf(".");
return 0;
}
}
}
printf("Sorted sequence cannot be determined.");
}
拓扑排序
#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
using namespace std;
int cnt, n, m, type, d[26], f[26];
bool st[26]; //记录当前节点是否出现过
void topsort(int i, vector<int> graph[]) {
queue<int> q;
memcpy(d, f, sizeof f);
//初始时将所有入度为0的节点入队
for (int i = 0; i < n; ++i) {
if (d[i] == 0) q.push(i);
}
string ans;
bool unique = true;
while (!q.empty()) {
//特判不能同时有两个入度为0的点存在,例如A->B , C->D,这两个序列显然不能推出关系
if (q.size() > 1) {
unique = false;//一定是最小的入栈,排序是一条链
}
int cur = q.front();
char ch = 'A' + cur;
ans += ch;
q.pop();
for (int ne : graph[cur]) {
if (--d[ne] == 0) q.push(ne);
}
}
//如果序列合法的话拓扑排序可以将所有节点的入度变为0,反之就是不合法
if (ans.size() < cnt) {
type = 2;//有环
printf("Inconsistency found after %d relations.\n", i);
}
//合法的条件就是
if(ans.size() == n && unique) {
type = 1;
printf("Sorted sequence determined after %d relations: %s.\n", i, ans.c_str());
}
}
int main() {
string s;
while (cin >> n >> m, n || m) {
memset(f, 0, sizeof f);
memset(st, 0, sizeof st);
type = 0;
cnt = 0; //记录当前出现的元素个数
vector<int> graph[26];
for (int i = 1; i <= m; ++i) {
cin >> s;
if (type) continue;
int a = s[0] - 'A', b = s[2] - 'A';
if (!st[a]) {
st[a] = true;//多一个变量
++cnt;
}
if (!st[b]) {
st[b] = true;//多一个变量
++cnt;
}
graph[a].push_back(b);
f[b]++;
topsort(i, graph);
}
if (!type) printf("Sorted sequence cannot be determined.\n");
}
return 0;
}
最小环
k
是不算i
、j
中间点的最大值,满足三角不等式
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110;
int n, m;
int d[N][N], g[N][N];
int pos[N][N];
int path[N], cnt;
const int INF = 0x3f3f3f3f;
void get_path(int i, int j)
{
if(pos[i][j] == 0) return;
int k = pos[i][j];
get_path(i, k);
path[cnt ++] = k;
get_path(k, j);
}
int main()
{
cin >> n >> m;
memset(g, 0x3f, sizeof g);
for(int i = 1; i <= n; i ++ )g[i][i] = 0;
while(m --)
{
int a, b, c;
cin >> a >> b >> c;
g[a][b] = g[b][a] = min(g[a][b], c);
}
int res = INF;
memcpy(d, g, sizeof d);
for(int k = 1; k <= n; k ++ )
{
for(int i = 1; i < k; i ++ )
for(int j = i + 1; j < k; j ++ )
if((long long)d[i][j] + g[j][k] + g[i][k] < res)
{
res = d[i][j] + g[j][k] + g[i][k];
cnt = 0;
path[cnt ++] = k;
path[cnt ++] = i;
get_path(i, j);
path[cnt ++] = j;
};
for(int i = 1; i <= n; i ++ )
{
for(int j = 1; j <= n; j ++ )
{
if(d[i][j] > d[i][k] + d[k][j])
{
d[i][j] = d[i][k] + d[k][j];
pos[i][j] = k;
}
}
}
}
if(res == INF) puts("No solution.");
else
{
for(int i = 0; i < cnt; i ++ )cout << path[i] << " ";
cout << endl;
}
}