100078D Domestic Networks
题目大意
有两种染料,给定它们的单价和数量,每染色一米需耗费一个单位的染料,一条边只能用一种燃料,给你一张图,要求你将其中的一些边染色使得在满足图联通的情况下花费最小并输出方案。
分析
首先,要求图联通且花费最小我们不由想到了求最小生成树,在求完之后我们的问题就变成的看每条边要被染成哪种颜色。我们用dpij表示考虑了前i条边,第一种染料(5号染料)用的数量,并用数组记录一下在这种情况下所选的染料种类就可以了,详见代码。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
#define sp cout<<"---------------------------------------------------"<<endl
const int inf=0x3f3f3f3f;
struct node {
int x,y,z,id;
}d[10002];
int dp[1002][10002],pre[1002],p5,q5,p6,q6,n,m,wh[1002],fa[1002],cnt,tot;
bool ch[1002][10002];
struct ans {
int a,b;
}out[10010];
bool cmp(const node a,const node b){return a.z<b.z;}
bool cmp2(const ans a,const ans b){return a.a<b.a;}
inline int sf(int x){return fa[x]==x?x:fa[x]=sf(fa[x]);}
int main(){
freopen("domestic.in","r",stdin);
freopen("domestic.out","w",stdout);
int i,j,k;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++){
scanf("%d%d%d",&d[i].x,&d[i].y,&d[i].z);
d[i].id=i;
}
scanf("%d%d%d%d",&p5,&q5,&p6,&q6);
sort(d+1,d+m+1,cmp);
for(i=1;i<=n;i++)fa[i]=i;
for(i=1;i<=m;i++){
if(sf(d[i].x)!=sf(d[i].y)){
fa[sf(d[i].x)]=sf(d[i].y);
cnt++;
pre[cnt]=pre[cnt-1]+d[i].z;
wh[cnt]=i;
}
if(cnt==n-1)break;
}
if(cnt<n-1){
puts("Impossible");
return 0;
}
memset(dp,0x3f,sizeof(dp));
dp[0][0]=0;
for(i=1;i<=cnt;i++)
for(j=0;j<=min(q5,pre[i]);j++){
if(pre[i]-j>=d[wh[i]].z&&pre[i]-j<=q6)
dp[i][j]=dp[i-1][j]+d[wh[i]].z*p6;
if(j>=d[wh[i]].z&&dp[i][j]>dp[i-1][j-d[wh[i]].z]+d[wh[i]].z*p5){
dp[i][j]=dp[i-1][j-d[wh[i]].z]+d[wh[i]].z*p5;
ch[i][j]=1;
}
}
int ans=inf,pl;
for(i=0;i<=q5;i++){
if(dp[cnt][i]<ans){
ans=dp[cnt][i];
pl=i;
}
}
if(ans==inf)puts("Impossible");
else {
cout<<ans<<endl;
for(i=cnt;i>0;i--)
if(ch[i][pl]){
cout<<d[wh[i]].id<<' '<<5<<endl;
pl-=d[wh[i]].z;
}else cout<<d[wh[i]].id<<' '<<6<<endl;
}
return 0;
}