http://acm.hdu.edu.cn/showproblem.php?pid=3339
这题还是有点水性的.......没说的,一次AC
一个类似于背包的DP
1)要使用滚动数组
2)先用dijskstra处理一下map[0][i]
其他的就没什么了......代码如下:
/*
* File: main.cpp
* Author: mtttt
*
* Created on 2010年3月15日, 上午10:57
*/
#include <stdlib.h>
#include <iostream>
const int MAX=20000000;
using namespace std;
int map[101][101];
int a[101];
bool used[101];
int aa[10001],bb[10001];
int n,m,tot;
/*
* ((tot+1)/2-1)的电最大的线路长度,<=>摧毁大于一半的电需要的最小路程,得出解
*/
void init()
{
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
map[i][j]=MAX;
for(int i=0;i<=n;i++)
used[i]=false;
tot=0;
}
void input()
{
int s,d,l;
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&s,&d,&l);
if(map[s][d]>l)
{
map[s][d]=l;
map[d][s]=l;
}
}
for(int i=1;i<=n;i++)
{scanf("%d",a+i);
tot+=a[i];
}
}
void dijkstra()
{
int k;
for(int i=1;i<=n;i++)
{ int min=MAX;
for(int j=1;j<=n;j++)
if(!used[j]&&map[0][j]<min)
min=map[0][j],k=j;
used[k]=true;
if(min==MAX) break;
for(int j=1;j<=n;j++)
{
if(!used[j]&&map[0][j]>map[0][k]+map[k][j])
map[0][j]=map[0][k]+map[k][j];
}
}
return ;
}
void dp()
{
int i,j;
for(int i=0;i<=10000;i++)
aa[i]=bb[i]=0;
tot=(tot+1)/2-1;
for(i=1;i<=n;i++)
{
for(j=1;j<=tot;j++)
{
if(a[i]<=j)
{
if(map[0][i]+bb[j-a[i]]>bb[j])
aa[j]=map[0][i]+bb[j-a[i]];
else
aa[j]=bb[j];
}
else aa[j]=bb[j];
}
for(int k=1;k<=tot;k++)
bb[k]=aa[k];
}
int sum=0;
for(int i=1;i<=n;i++)
sum+=map[0][i];
sum=sum-bb[tot];
if(sum>=MAX) printf("impossible/n");
else
printf("%d/n",sum);
}
int main(int argc, char** argv) {
// freopen("1.in","r",stdin);
int case1;
cin>>case1;
while(case1--)
{
scanf("%d %d",&n,&m);
init();
input();
dijkstra();
dp();
}
return 1;
}