题意:
容器中有 n 种原子,现提供 m 种光子,这 n 种原子中能量之差等于提供的 m 种光子之一所具有的能量,就认为这两种原子是处在容器在是危险的,现在要求取走一些原子,使得容器中的原子处在一块是安全的,同时要求剩下的原子的能量和最大。
思路:
很明显的树形dp,每两个处于会产生危险的原子连一条无向边,注意建图完了可能是一个森林!
PS:不会有环么?我AC了以后才发现这个问题。。。网上都没提这事,不知道我没完全理解题?
View Code
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <iostream> 5 #include <cmath> 6 #include <map> 7 8 #define N 10000 9 #define M 100000 10 11 using namespace std; 12 13 map<int,int> mp; 14 15 int head[N],to[M],next[M],a[N],b[N],cnt,num,n,m,tc[N],dp[N][2]; 16 bool vis[N]; 17 18 inline void add(int u,int v) 19 { 20 to[cnt]=v; next[cnt]=head[u]; head[u]=cnt++; 21 } 22 23 void read() 24 { 25 mp.clear(); 26 memset(head,-1,sizeof head);cnt=0; 27 num=0; 28 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 29 for(int i=1;i<=m;i++) scanf("%d",&b[i]); 30 for(int i=1;i<=n;i++) 31 for(int j=i+1;j<=n;j++) 32 for(int k=1;k<=m;k++) 33 if(abs(a[i]-a[j])==b[k]) 34 { 35 if(mp[a[i]]==0) {mp[a[i]]=++num;tc[num]=a[i];} 36 if(mp[a[j]]==0) {mp[a[j]]=++num;tc[num]=a[j];} 37 int ta=mp[a[i]],tb=mp[a[j]]; 38 add(ta,tb),add(tb,ta); 39 } 40 } 41 42 void find(int u,int fa) 43 { 44 vis[u]=true; 45 for(int i=head[u];~i;i=next[i]) 46 if(to[i]!=fa) find(to[i],u); 47 48 dp[u][1]=tc[u];dp[u][0]=0; 49 for(int i=head[u];~i;i=next[i]) 50 if(fa!=to[i]) 51 { 52 dp[u][0]+=max(dp[to[i]][1],dp[to[i]][0]); 53 dp[u][1]+=dp[to[i]][0]; 54 } 55 } 56 57 void go() 58 { 59 memset(dp,0x8f,sizeof dp); 60 memset(vis,0,sizeof vis); 61 int ans=0; 62 for(int i=1;i<=num;i++) 63 if(!vis[i]) 64 { 65 find(i,-1); 66 ans+=max(dp[i][0],dp[i][1]); 67 } 68 printf("%d\n",ans); 69 } 70 71 int main() 72 { 73 while(scanf("%d%d",&n,&m),n||m) 74 { 75 read(); 76 go(); 77 } 78 return 0; 79 }