CSU 1817 Bones’s Battery Submit(二分+Floyd)
Bones’s Battery Submit
【题目链接】Bones’s Battery Submit
【题目类型】二分+Floyd
&题意:
有n个点,m条边,从点ui到点vi的费电量是di,要求对于任意的起点s和终点e,必须能遍历过所有的点一遍,并且充电的次数不超过k次(在任何一个点都可以充满电),问电池容量最小是多少?
&题解:
首先求这种题,用二分还是可以想到的,那怎么判断是否可行就比较难了;
首先用floyd求出每2点之间的最短路,之后在写出一个dp数组,根据求出的dis最短距离,来求出从任意的u点到任意的v点在走过全图的情况下最少冲了多少次电,如果其中充电次数最多的小于等于k,那么就可行.
【时间复杂度】O(n^3log1e11)
&代码:
#include <cstdio>
#include <iostream>
#include <set>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <map>
#include <queue>
#include <vector>
using namespace std;
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
using ll=long long;
const int maxn= 1e3 +9;
ll dis[maxn][maxn],dp[maxn][maxn];
int n,k,m;
void floyd(ll arr[][maxn])
{
for(int i=0;i<n;i++) arr[i][i]=0;
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
if(arr[i][k]==LINF||i==k) continue;
arr[i][j]=min(arr[i][j],arr[i][k]+arr[k][j]);
}
}
void init()
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
dis[i][j]=LINF;
}
}
bool ok(ll cap)
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
if(dis[i][j]==LINF) return false;
dp[i][j]=dis[i][j]<=cap?1:LINF;
}
floyd(dp);
// for(int i=0;i<n;i++){
// for(int j=0;j<n;j++){
// printf("%lld ",dp[i][j]);
// }
// puts("");
// }
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
if(dp[i][j]>k) return false;
}
return true;
}
int main()
{
// ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
// freopen("E:1.txt","r",stdin);
int T;scanf("%d",&T);
while(T--){
scanf("%d%d%d",&n,&k,&m);
init();
for(int i=0;i<m;i++){
int u,v;
ll d;
scanf("%d%d%lld",&u,&v,&d);
dis[u][v]=dis[v][u]=d;
}
floyd(dis);
ll l=0,r=1e11+9,mid;
while(l<=r){
mid=(l+r)/2;
if(ok(mid)) r=mid-1;
else l=mid+1;
}
printf("%lld\n",l);
}
return 0;
}