1. dfs+强剪枝
题目大意:
给出1-n(<30)个点的地图,求一条路径使得经过所有点(每个点一次),并且使得路径距离和最小——注意:这里的路径和是每个点的累加:比如1-2-3-4;距离和:1-2,1-2-3,1-2-3-4 所有距离和。
解决:
floyd松弛所有边;
暴搜找最优解;
强剪枝——技巧!
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define inf 0x3f3f3f3f
#define db(a, b) cout<<a<<" " <<b<<endl
using namespace std;
const int maxn = 2e6+10;
typedef long long ll;
//思路错误:是求从1到经过其他所有点的一条完整路径的最短距离(说明题意:题目中求的是一条路径上的累加sum),而不是每个最短路径之和---太傻了!
//松弛+dfs+剪枝
int d[45], mp[45][45], pd[45];
int vis[45];
int n;
int ans;
void floyd(){
for(int k = 1; k <= n; k++){
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
if(mp[i][j]>mp[i][k]+mp[k][j]){
mp[i][j]=mp[i][k]+mp[k][j];
}
}
}
}
}
void dfs(int u, int cnt, int sum){
//剪枝
if(sum+vis[u]*(n-cnt)>ans) return;
//这里的剪枝
/*if(u>1&&pd[u]<sum){
ans = inf;
return;
}*/
for(int i = 2; i <= n; i++){
//思路修正:从此状态深入深搜,肯定经过当前u,之后的i有一个不满足,此条路肯定到不了所有点,所以剪枝了
if(vis[i] == -1 && vis[u]+mp[u][i]>pd[i]) return;
}
if(cnt == n){
if(ans>sum){
ans = sum;
}
return;
}
for(int i = 2; i <= n; i++){
if(vis[i] == -1){
vis[i] = vis[u]+mp[u][i];
dfs(i, cnt+1, sum+vis[i]);
vis[i] = -1;
}
}
}
int main(){
while(~scanf("%d", &n)){
ans = inf;
memset(d, inf, sizeof(d));
memset(vis, -1, sizeof(vis));
memset(mp, inf, sizeof(mp));
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
scanf("%d", &mp[i][j]);
}
}
for(int i = 2; i <= n; i++){
scanf("%d", &pd[i]);
}
floyd();
vis[1] = 0;
dfs(1, 1, 0);
if(ans!=inf) printf("%d\n", ans);
else printf("-1\n");
}
return 0;
}
2. Dijkstra板子复习
自己错的原因:d[ ]数组,没有根据mp[ ][ ]初始化 ,所以dijkstra就没有开始——找不到第一个最近点(因为vis[ ]标记)。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define inf 0x3f3f3f3f
#define db(a, b) cout<<a<<" " <<b<<endl
using namespace std;
const int maxn = 2e6+10;
typedef long long ll;
ll x[maxn], y[maxn], z[maxn];
ll d[1005], mp[1005][1005];
int vis[1005];
int n, m;
void dijkstra(){
for(int i = 0; i < n; i++){
d[i] = mp[0][i];
}
//问题出在这,如果只是d[0]=0,出现问题:只有7,因为直接找一个非起点本身的最近点,如果没有初始化直接到达可进点,就不能运行djkstra
//自己的问题:初始化不能丢
vis[0] = 1;
for(int i = 0; i < n-1; i++){
int u = -1;
ll mind = inf;
for(int j = 0; j < n; j++){
if(!vis[j] && d[j]<mind){
mind = d[j];
u = j;
}
}
if(u == -1){return;}
vis[u] =1;
for(int j = 1; j < n; j++){
if(!vis[j] && d[j]>d[u]+mp[u][j]){
d[j] = d[u]+mp[u][j];
}
}
}
}
int main(){
while(~scanf("%d%d%lld%lld%lld%lld", &n, &m, &x[0], &x[1], &y[0], &y[1])){
memset(d, inf, sizeof(d));
memset(vis, 0, sizeof(vis));
memset(mp, inf, sizeof(mp));
z[0] = (x[0]*90123+y[0])%8475871+1;
z[1] = (x[1]*90123+y[1])%8475871+1;
for(int i = 2; i < n*n; i++){
x[i] = (12345+x[i-1]*23456+x[i-2]*34567+x[i-1]*x[i-2]*45678)%5837501;
y[i] = (56789+y[i-1]*67890+y[i-2]*78901+y[i-1]*y[i-2]*89012)%9860381;
z[i] = (x[i]*90123+y[i])%8475871+1;
}
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
if(i!=j)mp[i][j]=z[i*n+j];
else mp[i][j] = 0;
//db("aaaaa---", mp[i][j]);
}
}
//Dijkstra有问题吗?
dijkstra();
ll ans = inf;
for(int i = 1; i < n; i++){
ans = min(d[i]%m, ans);
}
printf("%lld\n", ans);
}
return 0;
}