POJ 1639 Picnic Planning
http://poj.org/problem?id=1639
题目大意:给定一个图,求最小生成树,其中某个节点的度数小于K。
这就是一个最小k限度生成树,我写了好久好久,也有我不熟悉STL的原因,CE了好久……
求最小K度生成树的方法:首先去掉特殊点(v0),然后图会成为x个联通块,求x次最小生成树,然后将这x个生成树连接到v0上。
每次寻找一个点p,满足点p不与v0相联系(边不在生成树上,不是不相连),且与点p相关的在生成树上的边大于点p到v0的距离,舍弃原来的边,并将点p与v0相连。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <utility>
#include <iterator>
#include <cassert>
#include <cctype>
#include <list>
#include <bitset>
#include <cmath>
#include <functional>
#include <set>
#include <sstream>
#include <ctime>
#define mn 301
#define mm 1000
#define inf ~0u>>1
using namespace std;
struct EDGE{
int pnt,dist;
EDGE *pre;
EDGE (){}
EDGE(int _pnt,int _dist,EDGE *_pre):pnt(_pnt),dist(_dist),pre(_pre){}
}Edge[mm*2],*SP=Edge,*edge[mm];
map<string,int> NameList;
char place1[100],place2[100];
int x,y,z,n,names=1,MST,belong[mn],size[mn],blocks,dist[mn],pre[mn],big[mn],K,Link[mn],Point[mn],Degree,places;
bool use[mn][mn],vis[mn];
inline void addedge(int a,int b,int c){
edge[a]=new(++SP)EDGE(b,c,edge[a]);
edge[b]=new(++SP)EDGE(a,c,edge[b]);
}
int NameOrder(char s[100]){
if(NameList.find(s)==NameList.end()) NameList[s]=++names;
else return NameList[s];
return names;
}
void Count_Connection_Blocks(int x){
vis[x]=true,belong[x]=blocks,size[blocks]++;
for(EDGE *j=edge[x];j;j=j->pre)
if(!vis[j->pnt]) Count_Connection_Blocks(j->pnt);
}
void Prim(int cur){
for(int i=1;i<=names;i++) dist[i]=inf;
for(int i=1;i<=names;i++)
if(belong[i]==cur){
dist[i]=0;
break;
}
for(int k=1;k<=size[cur];k++){
int mind=inf,minp;
for(int i=1;i<=names;i++)
if(!vis[i] && mind>dist[i])
mind=dist[i],minp=i;
MST+=dist[minp],vis[minp]=true;
for(EDGE *j=edge[minp];j;j=j->pre)
if(!vis[j->pnt] && dist[j->pnt]>j->dist)
dist[j->pnt]=j->dist,pre[j->pnt]=minp;
}
}
void Mark(int u,int v,bool symble){
use[u][v]=symble,use[v][u]=symble;
}
void DP(int x,int fa){
pre[x]=fa;
for(EDGE *j=edge[fa];j;j=j->pre)
if(j->pnt==x){
if(fa!=1) big[x]=max(big[fa],j->dist);
else big[x]=0;
break;
}
for(EDGE *j=edge[x];j;j=j->pre)
if(use[x][j->pnt] && j->pnt!=fa) DP(j->pnt,x);
}
int main(){
scanf("%d",&n);
NameList["Park"]=1;
for(int i=1;i<=n;i++){
scanf("%s%s%d",place1,place2,&z);
addedge(NameOrder(place1),NameOrder(place2),z);
}
scanf("%d",&K);
vis[1]=true;
for(int i=2;i<=names;i++)
if(!vis[i]){
blocks++;
Count_Connection_Blocks(i);
}
memset(vis,false,sizeof(vis));vis[1]=true;
for(int i=1;i<=blocks;i++) Prim(i);
for(int i=2;i<=n;i++) Mark(pre[i],i,true);
memset(Link,0x7f,sizeof(Link));
for(EDGE *j=edge[1];j;j=j->pre)
if(Link[belong[j->pnt]]>j->dist)
Link[belong[j->pnt]]=j->dist,Point[belong[j->pnt]]=j->pnt;
for(int i=1;i<=blocks;i++){
MST+=Link[i];
Mark(1,Point[i],true);
}
Degree=blocks;
addedge(0,1,0);
DP(1,0);
while(Degree<K){
int maxd=0,maxp=0;
for(EDGE *j=edge[1];j;j=j->pre)
if(!use[1][j->pnt] && big[j->pnt]-j->dist>maxd)
maxd=big[j->pnt]-j->dist,maxp=j->pnt;
if(!maxp) break;
MST-=maxd,Degree++;
int i=maxp;EDGE *j;
while(true){
for(j=edge[i];j;j=j->pre)
if(j->pnt==pre[i]) break;
if(j->dist==big[maxp]) break;
else i=pre[i];
}
Mark(i,pre[i],false);
pre[maxp]=1;DP(maxp,1);
}
printf("Total miles driven: %d\n",MST);
return 0;
}

浙公网安备 33010602011771号