Prim持续等待更新!!!复杂度 O(n*n)
算法:最小生成树Kruskal 复杂度 O(E)
题目传送门:POJ1251
题意:给定n,接下来n-1行,每一行表示这个树跟其他点相连的距离!!!然根本不需要考虑重边!!!直接裸题!!!
//#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define sa(t) scanf("%d",&t)
#define SA(t) scanf("%lld", %t)
#define PF(t) printf("%lld",t)
#define pf(t) printf("%d", t)
#define PFF(t) printf("%lld\n",t)
#define pff(t) printf("%d\n", t)
typedef long long int ll;
void read(int &x)
{
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f;
}
using namespace std;
const int maxn = 10004;
int fa[maxn];
int Find(int x){
if(fa[x] == x)
return x;
else
return fa[x] = Find(fa[x]);
}
struct node{
int a,b,val;
}pp[maxn];
bool cmp(node a, node b){
return a.val < b.val;
}
void init(int n){
for(int i = 0; i <= n+1; i++)
fa[i] = i;
}
int main(){
int n;
while(cin>>n,n){
if( n == 0 )
break;
init(n);
char x,y;
int m,mm;
int cnt = 0, ans = 0;
for(int i = 1; i < n; i++){
cin>>x>>m;
for(int j = 1; j <=m;j++){
cin>>y>>mm;
pp[cnt].val =mm;
pp[cnt].a = x-'A';
pp[cnt].b = y - 'A';
cnt++;
}
}
sort(pp,pp+cnt,cmp);
for(int i = 0; i < cnt; i++){
int x = pp[i].a;
int y = pp[i].b;
if(Find(x) != Find(y)){
fa[Find(x)] = Find(y);
ans = ans + pp[i].val;
}
}
pff(ans);
}
return 0;
}
题目传送门:POJ1287
题意: n,m表示的就是n颗树,接下来m条边,然后套…
我的理解: 我感觉我不改做这个数据结构专题的!!!(⊙o⊙)…
这个题目吧!我开始想错了!我看了有重边!本来想去重边!后来我发现了!完全不需要!!还是菜!!继续刷吧!!!
//#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define sa(t) scanf("%d",&t)
#define SA(t) scanf("%lld", %t)
#define PF(t) printf("%lld",t)
#define pf(t) printf("%d", t)
#define PFF(t) printf("%lld\n",t)
#define pff(t) printf("%d\n", t)
typedef long long int ll;
void read(int &x)
{
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f;
}
using namespace std;
const int maxn = 10004;
int fa[maxn];
int Find(int x){
if(fa[x] == x)
return x;
else
return fa[x] = Find(fa[x]);
}
struct node{
int a,b,val;
}pp[maxn];
bool cmp(node a, node b){
return a.val < b.val;
}
void init(int n){
for(int i = 0; i <= n+1; i++)
fa[i] = i;
}
void add(int a,int b,int val,int cnt){
pp[cnt].a = a;
pp[cnt].b = b;
pp[cnt].val = val;
}
int main(){
int n, m, cc, ans, cnt, x, y, val;
while(sa(n) && n){
sa(m);
init(n);
cc = 0, ans = 0, cnt = 0;
for(int i = 0; i < m; i++){
sa(x),sa(y),sa(val);
add(x,y,val,cnt++);
}
sort(pp, pp+cnt, cmp);
for(int i = 0; i
题目传送门:POJ2031
题意: 告诉你n个球!然后的话,接下来n行表示的就是这个球空间坐标以及这个半径!然后这个题目需要你做的就是实现n个球相互连起来!你可以去搭建桥梁!求最小的长度!
我的理解: 一开始想了好久!然后想了下!可以直接用并查集!然后就是去考虑这个怎么去建边(建树)的过程了!仔细想想其实很简单!就是自己去判断这个两个球的位置关系!然后突然想两个都行下!!!
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define sa(t) scanf("%d",&t)
#define SA(t) scanf("%lld", %t)
#define PF(t) printf("%lld",t)
#define pf(t) printf("%d", t)
#define PFF(t) printf("%lld\n",t)
#define pff(t) printf("%d\n", t)
using namespace std;
struct node{
double x, y, z, r;
}; // pp[maxn]
struct edge{
int from, to;
double dis;
}; // e[maxn]
const int maxn = 105;
const double eps = 1e-10;
int fa[maxn];
edge e[maxn*maxn]; //表示的就是边
node pp[maxn];
int n,m; // n 是点 m是边
double dis(node v1,node v2){ //算空间的距离
double tmp;
tmp = sqrt( (v1.x-v2.x)*(v1.x-v2.x) + (v1.y-v2.y)*(v1.y-v2.y) +
(v1.z-v2.z)*(v1.z-v2.z) ) - v1.r - v2.r;
if( tmp < eps )
return 0.0;
else
return tmp;
}
int Find(int x){
return x == fa[x] ? x : fa[x] = Find(fa[x]);
}
bool merge(int a, int b){ // 返回为真表示的就是不需要加边
int x = Find(a);
int y = Find(b);
if( x == y ){
return true;
}else{
fa[x] = y;
}
return false;
}
bool cmp(edge a, edge b){ //重写排序
return a.dis < b.dis;
}
void Kruskal( ){
for(int i = 1; i <= n; i++)
fa[i] = i;
sort(e,e+m,cmp);
double ans = 0.0;
for(int i = 0; i < m; i++){
int x = Find(e[i].from);
int y = Find(e[i].to);
if(!merge(x,y)) // 表示需要加答案
ans += e[i].dis;
}
printf("%.3f\n",ans); //这里是坑啊
}
int main(){
while(sa(n)&&n){
if(n == 0)
break;
m = 0;
for(int i = 1; i <=n; i++ ){
scanf("%lf%lf%lf%lf",&pp[i].x,&pp[i].y,&pp[i].z,&pp[i].r);
for(int j = 1; j < i; j++){
e[m].from = j;
e[m].to = i;
e[m++].dis = dis(pp[i],pp[j]); //求的就是两个点的距离
}
}
Kruskal( );
}
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define sa(t) scanf("%d",&t)
#define SA(t) scanf("%lld", %t)
#define PF(t) printf("%lld",t)
#define pf(t) printf("%d", t)
#define PFF(t) printf("%lld\n",t)
#define pff(t) printf("%d\n", t)
using namespace std;
struct node{
double x, y, z, r;
}; // pp[maxn]
struct edge{
int from, to;
double dis;
};
const int maxn = 105;
const double inf = 4000;
const double eps = 1e-10;
double tree[maxn][maxn];
double dis[maxn];
edge e[maxn*maxn]; //表示的就是边
node pp[maxn];
int n,m; // n 是点 m是边
int vis[maxn];
double dist(node v1,node v2){ //算空间的距离
double tmp;
tmp = sqrt( (v1.x-v2.x)*(v1.x-v2.x) + (v1.y-v2.y)*(v1.y-v2.y) +
(v1.z-v2.z)*(v1.z-v2.z) ) - v1.r - v2.r;
if( tmp < eps )
return 0.0;
else
return tmp;
}
double Prime()
{
double ans = 0;
for(int i = 1; i <= n; i++) dis[i] = inf;
dis[1] = 0; /** 第一个点入连通分量*/
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= n; i++)
{
int x;
double m = inf; /** 不断的找下一个距离连通分量最小的点*/
for(int y = 1; y <= n; y++) if(!vis[y] && dis[y] <= m) m = dis[x=y];
vis[x] = 1; /** 标记进入连通分量*/
ans += dis[x]; /** 加入总路径 */
for(int y = 1; y <= n; y++) if(!vis[y]) /**不断更新剩下未加入连通分量的点与连通分量的最短距离*/
dis[y] = min(dis[y], tree[x][y]);
}
return ans;
}
void solve(){ //make_tree
for(int i = 1 ; i <=n; i++)
for(int j = 1 ; j <=n; j++)
tree[i][j] =inf;
for(int i = 1; i <= n; i++)
scanf("%lf%lf%lf%lf",&pp[i].x,&pp[i].y,&pp[i].z,&pp[i].r);
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
if(i == j) tree[i][j] = 0;
else tree[i][j] =dist(pp[i],pp[j]);
tree[j][i] = tree[i][j];
}
}
}
int main(){
while(scanf("%d",&n)&&n){
if(n == 0 )
break;
solve();
printf("%.3f\n",Prime());
}
return 0;
}
题目传送门:POJ2421
题意: 给你一个矩阵!题意就是最小生成树!然后m条路已经相连起来!这题很容易RE
我的理解: 注意的地方就是你单组输入!!!
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define sa(t) scanf("%d",&t)
#define SA(t) scanf("%lld", %t)
#define PF(t) printf("%lld",t)
#define pf(t) printf("%d", t)
#define PFF(t) printf("%lld\n",t)
#define pff(t) printf("%d\n", t)
using namespace std;
struct node{
double x, y, z, r;
}; // pp[maxn]
struct edge{
int from, to;
double dis;
};
const int maxn = 105;
const int inf = 0x3f3f3f3f;
const double eps = 1e-10;
int tree[maxn][maxn];
int dis[maxn];
edge e[maxn*maxn]; //表示的就是边
node pp[maxn];
int n,m; // n 是点 m是边
int vis[maxn];
double dist(node v1,node v2){ //算空间的距离
double tmp;
tmp = sqrt( (v1.x-v2.x)*(v1.x-v2.x) + (v1.y-v2.y)*(v1.y-v2.y) +
(v1.z-v2.z)*(v1.z-v2.z) ) - v1.r - v2.r;
if( tmp < eps )
return 0.0;
else
return tmp;
}
int Prime()
{
int ans = 0;
for(int i = 1; i <= n; i++) dis[i] = inf;
dis[1] = 0; /** 第一个点入连通分量*/
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= n; i++)
{
int x = 0;
int m = inf; /** 不断的找下一个距离连通分量最小的点*/
for(int y = 1; y <= n; y++) if(!vis[y] && dis[y] <= m) m = dis[ x = y];
vis[x] = 1; /** 标记进入连通分量*/
ans += m; /** 加入总路径 */
for(int y = 1; y <= n; y++)
if(!vis[y]&&dis[y]>tree[x][y] ) /**不断更新剩下未加入连通分量的点与连通分量的最短距离*/
dis[y] = tree[x][y];
}
return ans;
}
void solve(){ //make_tree
int x;
for(int i = 1 ; i <=n; i++)
for(int j = 1 ; j <=n; j++){
scanf("%d",&x);
tree[i][j] =x;
}
// for(int i = 1; i <= n; i++)
// scanf("%lf%lf%lf%lf",&pp[i].x,&pp[i].y,&pp[i].z,&pp[i].r);
int m;
scanf("%d",&m);
while(m--){
int a,b;
scanf("%d%d",&a,&b);
tree[a][b] = 0;
tree[b][a] = 0;
}
}
int main(){
scanf("%d",&n);
solve();
printf("%d\n",Prime());
return 0;
}
题目传送门:Hdu1875
题意: 题目意思就是n个岛,现在需要他们相互连起来,然后有些小岛不能连!!!最后判断下这个情况是不是能相互连
我的理解: Prim中要是下一个m连通分量还是inf的话!说明就是不能所有的相连
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define sa(t) scanf("%d",&t)
#define SA(t) scanf("%lld", %t)
#define PF(t) printf("%lld",t)
#define pf(t) printf("%d", t)
#define PFF(t) printf("%lld\n",t)
#define pff(t) printf("%d\n", t)
using namespace std;
struct node{
int x, y;
double z, r;
}; // pp[maxn]
struct edge{
int from, to;
double dis;
};
const int maxn = 105;
const double inf = 0x3f3f3f3f;
const double eps = 1e-10;
double tree[maxn][maxn];
double dis[maxn];
edge e[maxn*maxn]; //表示的就是边
node pp[maxn];
int n,m; // n 是点 m是边
int vis[maxn];
double Prime()
{
double ans = 0.0;
for(int i = 1; i <= n; i++) dis[i] = inf;
dis[1] = 0.0; /** 第一个点入连通分量*/
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= n; i++)
{
int x = 0;
double m = inf; /** 不断的找下一个距离连通分量最小的点*/
for(int y = 1; y <= n; y++) if(!vis[y] && dis[y] <= m) m = dis[ x = y];
if(m == inf) //判断不能
return -1;
vis[x] = 1; /** 标记进入连通分量*/
ans += m; /** 加入总路径 */
for(int y = 1; y <= n; y++)
if(!vis[y]&&dis[y]>tree[x][y] ) /**不断更新剩下未加入连通分量的点与连通分量的最短距离*/
dis[y] = tree[x][y];
}
return ans;
}
void solve(){ //make_tree
int x;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
tree[i][j]=inf,tree[j][i]=inf;
for(int i = 1; i <= n; i++)
scanf("%d%d",&pp[i].x,&pp[i].y);
for(int i = 1 ; i <=n; i++)
for(int j = 1 ; j <=n; j++){
double tt = sqrt((pp[i].x-pp[j].x)*(pp[i].x-pp[j].x)+(pp[i].y-pp[j].y)*(pp[i].y-pp[j].y));
if(tt<=1000.0&&tt>=10.0){
tree[i][j] = tt;
tree[j][i] = tree[i][j];
}
}
// for(int i = 1; i <= n; i++)
// scanf("%lf%lf%lf%lf",&pp[i].x,&pp[i].y,&pp[i].z,&pp[i].r);
}
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
solve();
double xx = Prime();
if(xx == -1){
printf("oh!\n");
}
else
printf("%.1lf\n",xx*100);
}
return 0;
}