您的位置:首页 > 运维架构

HDU 3768 Shopping 【最短路好题!!! + 离散化跑最短路 + 暴力枚举】

2018-01-26 10:15 459 查看
传送门

// 题题: 给定一个无向图(n, m) , 和 s 个必经点, 问从起点1出发必经给s个点后再回到1的路径之和最小是多少.

// 思路: 这道题和我之前做的一道题很像, 所以我做这道题的时候几乎是秒做吧……xixi

我们首先有一个想法就是一定是这s个点先相互到达, 然后在从中选择两个到1最短距离加上就行啦. 然后可以注意到s只有10, 那么我们直接跑10次dij(优化的), 统计出该10个点到图中任意一个点的最短路径, 因为点的编号很大, 所以进行一次离散化就行啦, 然后我们直接暴力循环这10个点的所有情况, 也就是全排列一次, 然后每次用第一个和最后一个和1的最短距离相加, 中间的相加取一个最小的就是了, 一定可以出答案的. 具体细节请看代码.

AC Code

const ll INF = 1e18;
const int maxn = 1e5+5;
int cas=1;
int cnt, head[maxn];
struct node
{
int to, next; ll w;
bool operator < (const node& a) const {
return w > a.w;
}
} e[maxn<<1];

void add(int u, int v, ll w) {
e[cnt] = (node){v,head[u],w};
head[u] = cnt++;
}

void init() {
cnt = 0;
memset(head, -1, sizeof(head));
}

bool vis[maxn];
ll dis[15][maxn];
int n,m;
void dij(int st, int cnt)
{
priority_queue<node> q;
for (int i = 1 ; i <= n ; i ++) dis[cnt][i] = INF;
dis[cnt][st] = 0; Fill(vis,0);
q.push((node){st, 0, 0});
while (!q.empty()) {
node u = q.top();
q.pop();
if(vis[u.to]) continue;
vis[u.to] = 1;

for (int i = head[u.to]; ~i; i = e[i].next) {
node k = e[i];
if (dis[cnt][k.to] > dis[cnt][u.to] + k.w) {
dis[cnt][k.to] = dis[cnt][u.to] + k.w;
q.push((node){k.to, 0, dis[cnt][k.to]});
}
}
}
}
int f[15], v[15];
void solve()
{
init();
scanf("%d%d",&n, &m);
for (int i = 1 ; i <= m ; i ++) {
int u, v; ll w;
scanf("%d%d%lld", &u, &v, &w);
u++; v++;
add(u, v, w); add(v, u, w);
}
int q; scanf("%d", &q);
for (int i = 1 ; i <= q ; i ++) {
int x; scanf("%d",&x);
x++; dij(x, i);
f[i] = i; v[i] = x;  // 离散化点.并跑最短路
}
sort(f+1, f+1+q);
ll ans = INF;
do {
ll tmp = dis[f[1]][1];
for (int i = 2 ; i <= q ; i ++) {
tmp += dis[f[i]][v[f[i-1]]];
}
tmp += dis[f[q]][1];
ans = min(ans, tmp);
}while(next_permutation(f+1, f+1+q));  // 暴力所有情况.
printf("%lld\n", ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: