题目:
http://acm.hdu.edu.cn/showproblem.php?pid=2682
题意:
有n个城市,每个城市有一个幸福值,对任意两个城市,如果两个城市中任意一个城市幸福值为素数或者两者之和为素数,那么这两个城市是可以连接的,代价是 min(min(vi,vj),|vi−vj|) ,求把所有城市连接再一起的最小花费,不能连通输出-1
思路:
最小生成树,测试prim模板
朴素的prim:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
using namespace std;
typedef pair<int, int> pii;
const int N = 600 + 10, M = 2000000 + 10, INF = 0x3f3f3f3f;
int g[N][N];
int mincost[N];
bool vis[N], prime[M];
int prim(int n)
{
memset(mincost, 0x3f, sizeof mincost);
memset(vis, 0, sizeof vis);
mincost[1] = 0;
int ans = 0, num = 0;
while(true)
{
int v = -1;
for(int i = 1; i <= n; i++)
if(! vis[i] && (v == -1 || mincost[i] < mincost[v])) v = i;
if(v == -1 || mincost[v] == INF) break;
vis[v] = true;
ans += mincost[v];
num++;
for(int i = 1; i <= n; i++) mincost[i] = min(mincost[i], g[v][i]);
}
return num == n ? ans : -1;
}
void table()
{
prime[0] = prime[1] = 1;
for(int i = 2; i * i < M; i++)
if(! prime[i])
for(int j = i + i; j < M; j += i) prime[j] = 1;
}
int main()
{
table();
int t, n, a[N];
scanf("%d", &t);
while(t--)
{
memset(g, 0x3f, sizeof g);
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
for(int i = 1; i <= n; i++)
for(int j = i + 1; j <= n; j++)
{
if(! prime[a[i]] || ! prime[a[j]] || ! prime[a[i]+a[j]])
{
int cost = min(min(a[i], a[j]), abs(a[i] - a[j]));
g[i][j] = g[j][i] = cost;
}
}
printf("%d\n", prim(n));
}
return 0;
}
二叉堆优化的prim:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
using namespace std;
typedef pair<int, int> pii;
const int N = 600 + 10, M = 2000000 + 10, INF = 0x3f3f3f3f;
struct edge
{
int to, cost, next;
}g[N*N*2];
int cnt, head[N];
int mincost[N];
bool vis[N], prime[M];
void add_edge(int v, int u, int cost)
{
g[cnt].to = u, g[cnt].cost = cost, g[cnt].next = head[v], head[v] = cnt++;
}
int prim(int n)
{
priority_queue<pii, vector<pii>, greater<pii> > que;
memset(vis, 0, sizeof vis);
memset(mincost, 0x3f, sizeof mincost);
que.push(pii(0, 1)), mincost[1] = 0;
int ans = 0, num = 0;
while(! que.empty())
{
int v = que.top().second; que.pop();
if(vis[v]) continue;
vis[v] = true;
num++;
ans += mincost[v];
for(int i = head[v]; i != -1; i = g[i].next)
{
int u = g[i].to;
if(mincost[u] > g[i].cost)
{
mincost[u] = g[i].cost;
que.push(pii(mincost[u], u));
}
}
}
return num == n ? ans : -1;
}
void table()
{
prime[0] = prime[1] = 1;
for(int i = 2; i * i < M; i++)
if(! prime[i])
for(int j = i + i; j < M; j += i) prime[j] = 1;
}
int main()
{
table();
int t, n, a[N];
scanf("%d", &t);
while(t--)
{
cnt = 0;
memset(head, -1, sizeof head);
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
for(int i = 1; i <= n; i++)
for(int j = i + 1; j <= n; j++)
{
if(! prime[a[i]] || ! prime[a[j]] || ! prime[a[i]+a[j]])
{
int cost = min(min(a[i], a[j]), abs(a[i] - a[j]));
add_edge(i, j, cost), add_edge(j, i, cost);
}
}
printf("%d\n", prim(n));
}
return 0;
}