好好读题比啥都重要
多源汇最短路,再加上 n 的范围如此之小,很明显是用floyd来做
比较暴力的写法是每一天,清洁完一轮,减少一轮灰尘度以后,执行一次floyd求最短路,然后再算P
#include <bits/stdc++.h>
using namespace std;
bool flag;
bool judge[105][105];
int sum;
int n,Q;
int D[105][105],L[105][105];
int f[105][105];
int edge(int d) //求总共有多少条边
{
int temp = 0;
for(int i = d - 1; i >= 1; i --) temp += i;
return temp;
}
void floyd()
{
for(int i = 0; i < n; i ++) //先初始化
{
for(int j = 0; j < n; j ++)
{
f[i][j] = D[i][j];
}
}
for(int i = 0; i < n; i ++) //floyd标准三层循环求最短路
{
for(int j = 0; j < n; j ++)
{
for(int k = 0; k < n; k ++)
{
f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
}
}
}
return;
}
int p() //用来求P
{
int P = 0;
for(int i = 0; i < n; i ++)
{
for(int j = 0; j < n; j ++)
P += f[i][j];
}
return P;
}
void clear(int x) //清理道路 x表示城市序号
{
x = x % n;
for(int i = 0; i < n; i ++)
{
if(i == x) continue; //自己跟自己就不用管了
if(judge[i][x] || judge[x][i]) continue; //这条路已到达下限
else
{
if(D[i][x] == L[i][x])
{
judge[i][x] = 1;
judge[x][i] = 1;
sum++; //表示有多少条边已经到达下限了
}
else
{
D[i][x] -= 1; //清理
D[x][i] -= 1;
}
}
}
return;
}
int main()
{
cin >> n >> Q;
for(int i = 0; i < n; i ++)
{
for(int j = 0; j < n; j ++)
{
cin >> D[i][j];
}
}
for(int i = 0; i < n; i ++)
{
for(int j = 0; j < n; j ++)
{
cin >> L[i][j];
}
}
for(int i = 0; !flag; i ++)
{
floyd();
if(p() <= Q) {cout << i; break;}
clear(i);
if(sum == edge(n)) flag = 1;
}
if(flag) cout << -1;
return 0;
}
floyd时间复杂度是n的三次方,n是100的话就10的六次方左右,感觉也差不多吧,于是交了一发暴力70分。。蓝桥国赛的数据还是不能轻视啊。。。
想来想去,偷偷看标签才知道
因为随着天数的增加,灰尘度一定单调递减,有这样的单调性,得用二分来优化啊
对天数进行二分,用check来判断是否符合要求,check里面对于每一个城市的治理次数要仔细判断,具体看代码;mod n 别忘了
#include <bits/stdc++.h>
using namespace std;
bool flag;
int n,Q;
int D[105][105],L[105][105];
int f[105][105];
void floyd()
{
for(int i = 0; i < n; i ++) //floyd标准三层循环求最短路
{
for(int j = 0; j < n; j ++)
{
for(int k = 0; k < n; k ++)
{
f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
}
}
}
return;
}
int p() //用来求P
{
int P = 0;
for(int i = 0; i < n; i ++)
{
for(int j = 0; j < n; j ++)
P += f[i][j];
}
return P;
}
bool check(int x)
{
int clear = x/n; //表示每个城市至少经历了多少轮治理
int city = (x - 1)%n; //表示有哪些城市是正在进行最新一轮的治理
for(int i = 0; i < n; i ++) //先初始化
{
for(int j = 0; j < n; j ++)
{
f[i][j] = D[i][j];
}
}
if(!x) //第0天就特判一下,直接floyd
{
floyd();
if(p() <= Q) return true;
else return false;
}
for(int i = 0; i < n; i ++)
{
for(int j = i + 1; j < n; j ++)
{
int dif;
if(i <= city) dif = clear + 1; //序号在city之后的城市是还没有轮到最新一轮治理的,治理数会小1
else dif = clear;
//接下来进行环境治理
if(D[i][j] - dif >= L[i][j])
{
f[i][j] = D[i][j] - dif;
f[j][i] = D[i][j] - dif;
}
else
{
f[i][j] = L[i][j];
f[j][i] = L[i][j];
}
}
}
floyd();
if(p() <= Q) return true;
else return false;
}
int main()
{
cin >> n >> Q;
for(int i = 0; i < n; i ++)
{
for(int j = 0; j < n; j ++)
{
cin >> D[i][j];
}
}
for(int i = 0; i < n; i ++)
{
for(int j = 0; j < n; j ++)
{
cin >> L[i][j];
}
}
int l = 0, r = 100000; //二分咯
while(l < r)
{
int mid = (l + r)/2;
if(check(mid)) flag = 1, r = mid; //如果有成功的flag变true
else l = mid + 1;
}
if(!flag) cout << -1;
else cout << l; //输出的是左指针l哦
return 0;
}