hdu 4966 最小树形图
生活随笔
收集整理的這篇文章主要介紹了
hdu 4966 最小树形图
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
將每門課等級拆成0,1,2,3...a[i]個點,對每一個等級大于0的點向它低一級連邊,權值為0【意思是,若修了level k。則level(0~k)都當做修了】
將輸入的邊建邊,權值為money[i]。
建立根節點,向每一個level 0的點連邊,權值為0【由于初始level 0的都修了】
因為題目要求每門課都必須達到最大level,也就是相應圖中根節點能到達全部點,問題就變成了求有向圖的最小生成樹。
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm>using namespace std; #define INF 0x3FFFFFF #define MAXN 5555 struct edge {int u,v,w; }e[9999999]; int n,en; int pre[MAXN],in[MAXN],id[MAXN],vis[MAXN]; void add(int u,int v,int w) {e[en].u=u;e[en].v=v;e[en++].w=w; } int zl(int root ,int vn) {int ans=0;int cnt;while(1){for(int i=0;i<vn;i++)in[i]=INF,id[i]=-1,vis[i]=-1;for(int i=0;i<en;i++){if(in[e[i].v]>e[i].w && e[i].u!=e[i].v){pre[e[i].v]=e[i].u;in[e[i].v]=e[i].w;}}in[root]=0;pre[root]=root;for(int i=0;i<vn;i++){ans+=in[i];if(in[i]==INF)return -1;}cnt=0;for(int i=0;i<vn;i++){if(vis[i]==-1){int t=i;while(vis[t]==-1){vis[t]=i;t=pre[t];}if(vis[t]!=i || t==root) continue;for(int j=pre[t];j!=t;j=pre[j])id[j]=cnt;id[t]=cnt++;}}if(cnt==0) break;for(int i=0;i<vn;i++)if(id[i]==-1)id[i]=cnt++;for(int i=0;i<en;i++){int u,v;u=e[i].u;v=e[i].v;e[i].u=id[u];e[i].v=id[v];e[i].w-=in[v];}vn=cnt;root=id[root];}return ans; } int a[MAXN],pres[MAXN]; int main() {int x,y,b,c,d,m;while(~scanf("%d%d",&n,&m)){if(!n&&!m) break;for(int i=1;i<=n;i++)scanf("%d",&a[i]),pres[i]=pres[i-1]+a[i]+1;en=0;int s=0;int t=pres[n]+1;for(int i=1;i<=n;i++){for(int id=1;id<=a[i];id++){add(pres[i-1]+id+1,pres[i-1]+id,0);// printf("%d -> %d\n",pres[i-1]+id+1,pres[i-1]+id);}add(s,pres[i-1]+1,0);// printf("%d -> %d\n",pres[i-1]+a[i]+1,t);// printf("%d -> %d\n",s,pres[i-1]+1);}for(int i=1;i<=m;i++){scanf("%d%d%d%d%d",&x,&y,&b,&c,&d);add(pres[x-1]+y+1,pres[b-1]+c+1,d);// printf("%d -> %d\n",pres[x-1]+y+1,pres[b-1]+c+1);}int tmp=zl(0,t);if(tmp<0) puts("-1");else printf("%d\n",tmp);}return 0; }總結
以上是生活随笔為你收集整理的hdu 4966 最小树形图的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 总结一些常用Android adb 命令
- 下一篇: meta的随堂笔记