给定一个n个点,m条边的无向图,其中你在第i个点建立旅游站点的费用为Ci。在这张图中,任意两点间不存在节点数超过10的简单路径。请找到一种费用最小的建立旅游站点的方案,使得每个点要么建立了旅游站点,要么与它有边直接相连的点里至少有一个点建立了旅游站点。
1 //minamoto 2 #include<iostream> 3 #include<cstdio> 4 using namespace std; 5 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 6 char buf[1<<21],*p1=buf,*p2=buf; 7 template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;} 8 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;} 9 inline int read(){ 10 #define num ch-'0' 11 char ch;bool flag=0;int res; 12 while(!isdigit(ch=getc())) 13 (ch=='-')&&(flag=true); 14 for(res=num;isdigit(ch=getc());res=res*10+num); 15 (flag)&&(res=-res); 16 #undef num 17 return res; 18 } 19 const int N=20005,M=50005,SS=60005,inf=0x3f3f3f3f; 20 int head[N],Next[M],ver[M],tot; 21 int a[N],f[15][SS],dep[N],vis[N],q[N],bin[15],top,n,m,res; 22 inline void add(int u,int v){ver[++tot]=v,Next[tot]=head[u],head[u]=tot;} 23 inline int get(int S,int dep){return S/bin[dep]%3;} 24 void dfs(int u,int d){ 25 dep[u]=d,vis[u]=1; 26 if(!d) f[0][0]=a[u],f[0][1]=0,f[0][2]=inf; 27 else{ 28 top=0; 29 for(int i=head[u];i;i=Next[i]) 30 if(vis[ver[i]]&&dep[ver[i]]<d) q[++top]=dep[ver[i]]; 31 for(int S=0;S<bin[d+1];++S) f[d][S]=inf; 32 for(int S=bin[d]-1;~S;--S){ 33 int U=1,V=S; 34 for(int i=1;i<=top;++i){ 35 int x=get(S,q[i]); 36 if(x==0) U=2; 37 else if(x==1) V+=bin[q[i]]; 38 } 39 cmin(f[d][S+U*bin[d]],f[d-1][S]); 40 cmin(f[d][V],f[d-1][S]+a[u]); 41 } 42 } 43 for(int i=head[u];i;i=Next[i]){ 44 int v=ver[i]; 45 if(!vis[v]){ 46 dfs(v,d+1); 47 for(int S=0;S<bin[d+1];++S) 48 f[d][S]=min(f[d+1][S],f[d+1][S+2*bin[d+1]]); 49 } 50 } 51 } 52 int main(){ 53 // freopen("testdata.in","r",stdin); 54 bin[0]=1;for(int i=1;i<=10;++i) bin[i]=bin[i-1]*3; 55 n=read(),m=read(); 56 for(int i=1;i<=n;++i) a[i]=read(); 57 for(int i=1,u,v;i<=m;++i) 58 u=read(),v=read(),add(u,v),add(v,u); 59 for(int i=1;i<=n;++i) 60 if(!vis[i]) dfs(i,0),res+=min(f[0][0],f[0][2]); 61 printf("%d\n",res); 62 return 0; 63 }