POJ2349二分+并查集,类似最小树的贪心
生活随笔
收集整理的這篇文章主要介紹了
POJ2349二分+并查集,类似最小树的贪心
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
題意:
? ? ? 給你n個(gè)點(diǎn),你的任務(wù)是構(gòu)建一顆通訊樹(shù),然后給你一個(gè)s表示可以選出來(lái)s個(gè)點(diǎn)兩兩通訊不花錢(qián),就是費(fèi)用是0,其他的費(fèi)用就是兩點(diǎn)的距離,有個(gè)要求就是其他的費(fèi)用中最大的那個(gè)最小。
思路:
? ? ?方法比較多,題目也不難,但是容易有一個(gè)誤區(qū)就是很多人認(rèn)為這個(gè)題目是在求最小生成樹(shù),我不是這么想的(雖然這個(gè)題目可以用最小樹(shù)的算法過(guò),但是我的感覺(jué)是他和最小樹(shù)是相同的代碼,不同的思想),因?yàn)樽钚?shù)畢竟是求全局和的最小,而這個(gè)題目是求全局中最大的最小,這樣首先容易讓人想到的就是直接二分,二分距離,然后去用并查集或者是搜索啥的去判斷聯(lián)通快個(gè)數(shù)啥的,這樣是很容易理解的,我試了下,可以ac,但是回來(lái)說(shuō)最小樹(shù),這個(gè)題目直接用最小樹(shù)的算法也可以ac,但是思路和最小樹(shù)的想法沒(méi)啥關(guān)系,在克魯斯卡爾里,大體思想是 排序后 如果當(dāng)前這兩個(gè)連通塊沒(méi)有連接,那么就直接用最小的代價(jià),也就是當(dāng)前的花費(fèi)去連接,因?yàn)樵缤矶嫉眠B接,不如趁現(xiàn)在最省的時(shí)候,就這樣貪心到最后就是最下生成樹(shù),但是這個(gè)題目的想法卻是,既然你是求最大的最小,那么我們排序后就一個(gè)一個(gè)往里面添加,知道滿足要求的時(shí)候就直接停止就行了。和最小樹(shù)的寫(xiě)法沒(méi)啥區(qū)別,但是理論依據(jù)不同,這個(gè)要清楚。還有就是我用兩種方法寫(xiě)了下(還可以有更多方法,什么二分+搜索啥的都行),其中一個(gè)是類似最小樹(shù)那樣,另一個(gè)是二分+并查集,我的二分里面沒(méi)啥大優(yōu)化,如果像更快的話,二分的時(shí)候可以直接二分任意兩點(diǎn)所有的距離,就是說(shuō)答案肯定是任意兩點(diǎn)距離中的一個(gè),這樣可以縮短二分范圍。。。。。
二分+并查集
#include<math.h>
#include<stdio.h>
#include<algorithm>
#define eps 0.000001
using namespace std;
typedef struct
{
? ? int x ,y;
}NODE;
typedef struct
{
? ? int a ,b;
? ? double c;
}EDGE;
NODE node[500+5];
EDGE edge[500*500/2+10];
int mer[500+5] ,n ,m;
bool camp(EDGE a ,EDGE b)
{
? ? return a.c < b.c;
}
int finds(int x)
{
? ? return x == mer[x] ? x : mer[x] = finds(mer[x]);
}
bool ok(int nowid ,double now)
{
? ? for(int i = 1 ;i <= n ;i ++)
? ? mer[i] = i;
? ? int s = 0;
? ? for(int i = 1 ;i <= nowid ;i ++)
? ? {
? ? ? ? if(edge[i].c > now) break;
? ? ? ? int x = finds(edge[i].a);
? ? ? ? int y = finds(edge[i].b);
? ? ? ? if(x == y) continue;
? ? ? ? s ++;
? ? ? ? mer[x] = y;
? ? ? ? if(s + m >= n) return 1;
? ? }
? ? return 0;
}
double Search2(int nowid)
{
? ? double low = 0 ,up = edge[nowid].c;
? ? double mid;
? ? while(up - low >= eps)
? ? {
? ? ? ? mid = (low + up) / 2;
? ? ? ? if(ok(nowid ,mid))
? ? ? ? up = mid - eps;
? ? ? ? else low = mid + eps;
? ? }
? ? return low;
}
double GetDis(NODE a ,NODE b)
{
? ? double x = (a.x - b.x) * (a.x - b.x);
? ? double y = (a.y - b.y) * (a.y - b.y);
? ? return sqrt(x + y);
}
int main ()
{
? ? int t ,i ,j ,nowid;
? ? scanf("%d" ,&t);
? ? while(t--)
? ? {
? ? ? ? scanf("%d %d" ,&m ,&n);
? ? ? ? nowid = 0;
? ? ? ? for(i = 1 ;i <= n ;i ++)
? ? ? ? {
? ? ? ? ? ? scanf("%d %d" ,&node[i].x ,&node[i].y);
? ? ? ? ? ? for(j = 1 ;j < i ;j ++)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? ++nowid;
? ? ? ? ? ? ? ? edge[nowid].a = i;
? ? ? ? ? ? ? ? edge[nowid].b = j;
? ? ? ? ? ? ? ? edge[nowid].c = GetDis(node[i] ,node[j]);
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? if(m >= n)
? ? ? ? {
? ? ? ? ? ? printf("0.00\n");
? ? ? ? ? ? continue;
? ? ? ? }
? ? ? ? sort(edge + 1 ,edge + nowid + 1 ,camp);
? ? ? ? printf("%.2lf\n" ,Search2(nowid));
? ? }
? ? return 0;
}
貪心+并查集
#include<math.h>
#include<stdio.h>
#include<algorithm>
using namespace std;
typedef struct
{
? ? int a ,b;
? ? double c;
}EDGE;
typedef struct
{
? ? int ?x ,y;
}NODE;
NODE node[500+5];
EDGE edge[500*500/2+10];
int mer[500+5];
bool camp(EDGE a ,EDGE b)
{
? ? return a.c < b.c;
}
int finds(int x)
{
? ? return x == mer[x] ? x : mer[x] = finds(mer[x]);
}
double GetDis(NODE a, NODE b)
{
? ? double x = (a.x - b.x) * (a.x - b.x);
? ? double y = (a.y - b.y) * (a.y - b.y);
? ? return sqrt(x + y);
}
int main ()
{
? ? int t ,n ,m ,i ,j;
? ? scanf("%d" ,&t);
? ? while(t--)
? ? {
? ? ? ? scanf("%d %d" ,&m ,&n);
? ? ? ? int nowid = 0;
? ? ? ? for(i = 1 ;i <= n ;i ++)
? ? ? ? {
? ? ? ? ? ? mer[i] = i;
? ? ? ? ? ? scanf("%d %d" ,&node[i].x ,&node[i].y);
? ? ? ? ? ? for(j = 1 ;j < i ;j ++)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? ++nowid;
? ? ? ? ? ? ? ? edge[nowid].c = GetDis(node[i] ,node[j]);
? ? ? ? ? ? ? ? edge[nowid].a = i ,edge[nowid].b = j;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? if(m >= n)
? ? ? ? {
? ? ? ? ? ? printf("0\n");
? ? ? ? ? ? continue;
? ? ? ? }
? ? ? ? sort(edge + 1 ,edge + nowid + 1 ,camp);
? ? ? ? int edges = 0;
? ? ? ? for(i = 1 ;i <= nowid ;i ++)
? ? ? ? {
? ? ? ? ? ? int x = finds(edge[i].a);
? ? ? ? ? ? int y = finds(edge[i].b);
? ? ? ? ? ? if(x == y)continue;
? ? ? ? ? ? edges ++;
? ? ? ? ? ? mer[x] = y;
? ? ? ? ? ? if(edges + m >= n)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? printf("%.2lf\n" ,edge[i].c);
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? return 0;
}
? ? ? 給你n個(gè)點(diǎn),你的任務(wù)是構(gòu)建一顆通訊樹(shù),然后給你一個(gè)s表示可以選出來(lái)s個(gè)點(diǎn)兩兩通訊不花錢(qián),就是費(fèi)用是0,其他的費(fèi)用就是兩點(diǎn)的距離,有個(gè)要求就是其他的費(fèi)用中最大的那個(gè)最小。
思路:
? ? ?方法比較多,題目也不難,但是容易有一個(gè)誤區(qū)就是很多人認(rèn)為這個(gè)題目是在求最小生成樹(shù),我不是這么想的(雖然這個(gè)題目可以用最小樹(shù)的算法過(guò),但是我的感覺(jué)是他和最小樹(shù)是相同的代碼,不同的思想),因?yàn)樽钚?shù)畢竟是求全局和的最小,而這個(gè)題目是求全局中最大的最小,這樣首先容易讓人想到的就是直接二分,二分距離,然后去用并查集或者是搜索啥的去判斷聯(lián)通快個(gè)數(shù)啥的,這樣是很容易理解的,我試了下,可以ac,但是回來(lái)說(shuō)最小樹(shù),這個(gè)題目直接用最小樹(shù)的算法也可以ac,但是思路和最小樹(shù)的想法沒(méi)啥關(guān)系,在克魯斯卡爾里,大體思想是 排序后 如果當(dāng)前這兩個(gè)連通塊沒(méi)有連接,那么就直接用最小的代價(jià),也就是當(dāng)前的花費(fèi)去連接,因?yàn)樵缤矶嫉眠B接,不如趁現(xiàn)在最省的時(shí)候,就這樣貪心到最后就是最下生成樹(shù),但是這個(gè)題目的想法卻是,既然你是求最大的最小,那么我們排序后就一個(gè)一個(gè)往里面添加,知道滿足要求的時(shí)候就直接停止就行了。和最小樹(shù)的寫(xiě)法沒(méi)啥區(qū)別,但是理論依據(jù)不同,這個(gè)要清楚。還有就是我用兩種方法寫(xiě)了下(還可以有更多方法,什么二分+搜索啥的都行),其中一個(gè)是類似最小樹(shù)那樣,另一個(gè)是二分+并查集,我的二分里面沒(méi)啥大優(yōu)化,如果像更快的話,二分的時(shí)候可以直接二分任意兩點(diǎn)所有的距離,就是說(shuō)答案肯定是任意兩點(diǎn)距離中的一個(gè),這樣可以縮短二分范圍。。。。。
二分+并查集
#include<math.h>
#include<stdio.h>
#include<algorithm>
#define eps 0.000001
using namespace std;
typedef struct
{
? ? int x ,y;
}NODE;
typedef struct
{
? ? int a ,b;
? ? double c;
}EDGE;
NODE node[500+5];
EDGE edge[500*500/2+10];
int mer[500+5] ,n ,m;
bool camp(EDGE a ,EDGE b)
{
? ? return a.c < b.c;
}
int finds(int x)
{
? ? return x == mer[x] ? x : mer[x] = finds(mer[x]);
}
bool ok(int nowid ,double now)
{
? ? for(int i = 1 ;i <= n ;i ++)
? ? mer[i] = i;
? ? int s = 0;
? ? for(int i = 1 ;i <= nowid ;i ++)
? ? {
? ? ? ? if(edge[i].c > now) break;
? ? ? ? int x = finds(edge[i].a);
? ? ? ? int y = finds(edge[i].b);
? ? ? ? if(x == y) continue;
? ? ? ? s ++;
? ? ? ? mer[x] = y;
? ? ? ? if(s + m >= n) return 1;
? ? }
? ? return 0;
}
double Search2(int nowid)
{
? ? double low = 0 ,up = edge[nowid].c;
? ? double mid;
? ? while(up - low >= eps)
? ? {
? ? ? ? mid = (low + up) / 2;
? ? ? ? if(ok(nowid ,mid))
? ? ? ? up = mid - eps;
? ? ? ? else low = mid + eps;
? ? }
? ? return low;
}
double GetDis(NODE a ,NODE b)
{
? ? double x = (a.x - b.x) * (a.x - b.x);
? ? double y = (a.y - b.y) * (a.y - b.y);
? ? return sqrt(x + y);
}
int main ()
{
? ? int t ,i ,j ,nowid;
? ? scanf("%d" ,&t);
? ? while(t--)
? ? {
? ? ? ? scanf("%d %d" ,&m ,&n);
? ? ? ? nowid = 0;
? ? ? ? for(i = 1 ;i <= n ;i ++)
? ? ? ? {
? ? ? ? ? ? scanf("%d %d" ,&node[i].x ,&node[i].y);
? ? ? ? ? ? for(j = 1 ;j < i ;j ++)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? ++nowid;
? ? ? ? ? ? ? ? edge[nowid].a = i;
? ? ? ? ? ? ? ? edge[nowid].b = j;
? ? ? ? ? ? ? ? edge[nowid].c = GetDis(node[i] ,node[j]);
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? if(m >= n)
? ? ? ? {
? ? ? ? ? ? printf("0.00\n");
? ? ? ? ? ? continue;
? ? ? ? }
? ? ? ? sort(edge + 1 ,edge + nowid + 1 ,camp);
? ? ? ? printf("%.2lf\n" ,Search2(nowid));
? ? }
? ? return 0;
}
貪心+并查集
#include<math.h>
#include<stdio.h>
#include<algorithm>
using namespace std;
typedef struct
{
? ? int a ,b;
? ? double c;
}EDGE;
typedef struct
{
? ? int ?x ,y;
}NODE;
NODE node[500+5];
EDGE edge[500*500/2+10];
int mer[500+5];
bool camp(EDGE a ,EDGE b)
{
? ? return a.c < b.c;
}
int finds(int x)
{
? ? return x == mer[x] ? x : mer[x] = finds(mer[x]);
}
double GetDis(NODE a, NODE b)
{
? ? double x = (a.x - b.x) * (a.x - b.x);
? ? double y = (a.y - b.y) * (a.y - b.y);
? ? return sqrt(x + y);
}
int main ()
{
? ? int t ,n ,m ,i ,j;
? ? scanf("%d" ,&t);
? ? while(t--)
? ? {
? ? ? ? scanf("%d %d" ,&m ,&n);
? ? ? ? int nowid = 0;
? ? ? ? for(i = 1 ;i <= n ;i ++)
? ? ? ? {
? ? ? ? ? ? mer[i] = i;
? ? ? ? ? ? scanf("%d %d" ,&node[i].x ,&node[i].y);
? ? ? ? ? ? for(j = 1 ;j < i ;j ++)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? ++nowid;
? ? ? ? ? ? ? ? edge[nowid].c = GetDis(node[i] ,node[j]);
? ? ? ? ? ? ? ? edge[nowid].a = i ,edge[nowid].b = j;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? if(m >= n)
? ? ? ? {
? ? ? ? ? ? printf("0\n");
? ? ? ? ? ? continue;
? ? ? ? }
? ? ? ? sort(edge + 1 ,edge + nowid + 1 ,camp);
? ? ? ? int edges = 0;
? ? ? ? for(i = 1 ;i <= nowid ;i ++)
? ? ? ? {
? ? ? ? ? ? int x = finds(edge[i].a);
? ? ? ? ? ? int y = finds(edge[i].b);
? ? ? ? ? ? if(x == y)continue;
? ? ? ? ? ? edges ++;
? ? ? ? ? ? mer[x] = y;
? ? ? ? ? ? if(edges + m >= n)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? printf("%.2lf\n" ,edge[i].c);
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? return 0;
}
總結(jié)
以上是生活随笔為你收集整理的POJ2349二分+并查集,类似最小树的贪心的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: POJ2308连连看dfs+bfs+优化
- 下一篇: POJ2446 模板盖格子 简单二分匹配