Bzoj1937 [Shoi2004]Mst 最小生成树
2017-04-14 16:58
344 查看
Submit: 651 Solved: 276
Description
Input
第一行为N、M,其中 表示顶点的数目, 表示边的数目。顶点的编号为1、2、3、……、N-1、N。接下来的M行,每行三个整数Ui,Vi,Wi,表示顶点Ui与Vi之间有一条边,其权值为Wi。所有的边在输入中会且仅会出现一次。再接着N-1行,每行两个整数Xi、Yi,表示顶点Xi与Yi之间的边是T的一条边。
Output
输出最小权值
Sample Input
6 91 2 2
1 3 2
2 3 3
3 4 3
1 5 1
2 6 3
4 5 4
4 6 7
5 6 6
1 3
2 3
3 4
4 5
4 6
Sample Output
8【样例说明】
边(4,6)的权由7修改为3,代价为4
边(1,2)的权由2修改为3,代价为1
边(1,5)的权由1修改为4,代价为3
所以总代价为4+1+3=8
修改方案不唯一。
HINT
1<=n<=50,1<=m<=800,1<=wi<=1000
n-->点数..m-->边数..wi--->边权
Source
图论 网络流 费用流 数学问题
看好多题解说这题是线性规划……迷
然而并不会线性规划,纯按网络流思路跑了一发,也能跑出来。
基本思想是让一个“可能形成的环”上的树边权值都比非树边小。
对于每一条非树边,DFS出它两端点之间的树链,对于树链上每一条边,如果它的权值比非树边小,就从树边向非树边连边,容量为1,费用为权值差(加权减权等价)。
源点向树边连边,非树边向汇点连边,容量1,费用0。
然后跑最大费用可行流,即是说,为了满足条件,每一条正向费用的弧都是必须调整的。
最大费用可行流就是SPFA跑最大路径,当S到T的最长路小于等于0时退出。
看错了边数范围,WA了俩小时,气
/*by SilverN*/ #include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<vector> #include<queue> #define LL long long using namespace std; const int mxn=100010; int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } vector<int>ve[120]; struct EG{ int x,y,w; }eg[mxn]; struct edge{ int u,v,nxt,f,w; }e[mxn<<2]; int hd[mxn],mct=1; void add_edge(int u,int v,int f,int w){ e[++mct].nxt=hd[u];e[mct].v=v;e[mct].u=u; e[mct].f=f;e[mct].w=w;hd[u]=mct;return; } void insert(int u,int v,int c,int w){ add_edge(u,v,c,w); add_edge(v,u,0,-w); return; } int n,m,S,T; int dis[1010]; int pre[mxn]; bool inq[mxn]; bool SPFA(){ memset(dis,-0x3f,sizeof dis); memset(pre,0,sizeof pre); int dd=dis[0]; dis[S]=0; queue<int>q; q.push(S); while(!q.empty()){ int u=q.front();q.pop(); inq[u]=0; for(int i=hd[u],v;i;i=e[i].nxt){ if(!e[i].f)continue; v=e[i].v; if(dis[v]<dis[u]+e[i].w){ dis[v]=dis[u]+e[i].w; pre[v]=i; if(!inq[v]){ inq[v]=1; q.push(v); } } } } return (dis[T]!=dd); } int MCF(){ // SPFA(); int res=0; while(SPFA()){ if(dis[T]<=0)break; int tmp=1e9; for(int x=pre[T];x;x=pre[e[x].u]) tmp=min(tmp,e[x].f); res+=tmp*dis[T]; for(int x=pre[T];x;x=pre[e[x].u]){ e[x].f-=tmp; e[x^1].f+=tmp; } } return res; } int mp[120][120],tp[120][120]; int id[120][120]; int fa[mxn]; void DFS(int u,int ff){ fa[u]=ff; for(int i=0;i<ve[u].size();i++){ if(ve[u][i]==ff)continue; DFS(ve[u][i],u); } return; } void Build(){ int i,j; S=0;T=m+1; for(i=1;i<=m;i++){ int x=eg[i].x,y=eg[i].y; if(mp[x][y])continue; DFS(y,0); for(;x!=y;x=fa[x]){ int tmp=mp[x][fa[x]]-eg[i].w; if(tmp>0)insert(id[x][fa[x]],i,1,tmp); } } for(i=1;i<=m;i++){ if(mp[eg[i].x][eg[i].y])insert(S,i,1,0); else insert(i,T,1,0); } return; } int main(){ int i,j; n=read();m=read(); for(i=1;i<=m;i++){ eg[i].x=read();eg[i].y=read();eg[i].w=read(); tp[eg[i].x][eg[i].y]=tp[eg[i].y][eg[i].x]=eg[i].w;; id[eg[i].x][eg[i].y]=i; id[eg[i].y][eg[i].x]=i;// } int x,y; for(i=1;i<n;i++){ x=read();y=read(); ve[x].push_back(y); ve[y].push_back(x); mp[x][y]=mp[y][x]=tp[x][y]; tp[x][y]=tp[y][x]=0; } Build(); int ans=MCF(); printf("%d\n",ans); return 0; }
相关文章推荐
- [BZOJ1937][Shoi2004]Mst 最小生成树(KM)
- 【KM】BZOJ1937 [Shoi2004]Mst 最小生成树
- bzoj1937 [Shoi2004]Mst 最小生成树(KM)
- bzoj 1937: [Shoi2004]Mst 最小生成树 费用流
- bzoj 1937: [Shoi2004]Mst 最小生成树 KM算法
- bzoj 1937: [Shoi2004]Mst 最小生成树
- 【bzoj1937】 Shoi2004—Mst 最小生成树
- bzoj 1937: [Shoi2004]Mst 最小生成树
- BZOJ 1937: [Shoi2004]Mst 最小生成树 [二分图最大权匹配]
- bzoj 1937: [Shoi2004]Mst 最小生成树 (KM算法)
- [BZOJ 1937][Shoi2004]Mst 最小生成树
- BZOJ 1937[Shoi2004]Mst 最小生成树
- [对偶 KM算法 生成树 || 最大费用可行流 || 线性规划] BZOJ 1937 [Shoi2004]Mst 最小生成树
- Bzoj1937:[Shoi2004]Mst 最小生成树:KM算法
- bzoj 1937: [Shoi2004]Mst 最小生成树
- 【BZOJ1937】[Shoi2004]Mst 最小生成树 KM算法(线性规划)
- [BZOJ1937][Shoi2004]Mst 最小生成树(KM)
- 【bzoj1937】[Shoi2004]Mst 最小生成树
- bzoj1937[Shoi2004]Mst 最小生成树
- [BZOJ1937][SHOI2004]Mst最小生成树(KM算法,最大费用流)