HDU4966

#include <stdio.h>//这是别人的题解 
#include <string.h>//A了 
#include <iostream>
#include <algorithm>
#include <math.h>
using namespace std;
const int INF = 100000000;
const int MAXN = 1010; //点数
const int MAXM = 1010000;//边数
struct EDGE
{
 int u,v,cost;
}edge[MAXM];
int v;
int pre[MAXN],visit[MAXN],sum[MAXN],in[MAXN],a[MAXN],id[MAXN];
int edgenum;

void add_edge(int u,int v,int cost)
{
	EDGE E={u,v,cost};
	edge[++edgenum]=E;
	//cout<<v<<" "<<cost<<endl;
}


int hash(int i,int j)
{
	return sum[i-1]+j;
}

int zhuliu(int root,int n,int m,EDGE edge[])//root为0 
{
	int res=0,tn;
//	cout<<m<<endl;
	while(1)
	{
	// cout<<m<<endl;
	for(int i=0;i<=n;i++)//n不对吧! 
	in[i]=INF;//不是啦,循环所有点 	
	//cout<<"*****"<<endl;
    for(int i=1;i<=m;i++)
	{
		//cout<<edge[i].u<<" "<<edge[i].v<<" "<<edge[i].cost<<endl;

		if(edge[i].v!=edge[i].u&&edge[i].cost<in[edge[i].v])
		{
	
		in[edge[i].v]=edge[i].cost;
		pre[edge[i].v]=edge[i].u;
	    }
	} 
	
//	cout<<pre[3]<<endl;
	for(int i=0;i<=n;i++)
	{
		//cout<<i<<" "<<in[i]<<endl;
		if(i!=root&&in[i]==INF)
		return -1;
	}
	memset(id,-1,sizeof(id));
	memset(visit,-1,sizeof(visit));
	in[root]=0;
	for(int i=0;i<=n;i++)
	res+=in[i];
	//cout<<res<<endl;
	//找自环
	tn=0;
	/*****/
	for(int i=0;i<=n;i++)
	{
		int u=i;
		while(u!=root&&visit[u]!=i&&id[u]==-1)//一直向前赋值,既然源节点不是root,那么他就是一个环 
		{
			visit[u]=i;
			u=pre[u];
		}
		if(u!=root&&id[u]==-1) 
		{	
		for(int v=pre[u];u!=v;v=pre[v]) 
			id[v]=tn;	
		id[u]=tn++;	
	    }
	
	}
	
	//cout<<tn<<endl;
	if(tn==0)
	break;
	//按边更新 
	for(int i=0;i<=n;i++)
	if(id[i]==-1)
	id[i]=tn++;
	//for(int i=0;i<=n;i++)
	//cout<<id[i]<<endl;
	//for(int i=1;i<=m;i++)
	//cout<<edge[i].u<<" "<<edge[i].v<<endl;

		for(int i = 1;i <=m;)//缩点 ,建立新图 
			{
				v = edge[i].v;
				//cout<<i<<" "<<edge[i].u<<" "<<edge[i].v<<endl;
				edge[i].u = id[edge[i].u];//是一个环中 
				edge[i].v = id[edge[i].v];
				if(edge[i].u != edge[i].v)
					edge[i++].cost -= in[v];
				else
					swap(edge[i],edge[--m+1]);//减边,而且把edge[i]放到后面。。。太绝了 
			}
	n=tn-1;
    root=id[root];
    //cout<<tn-1<<endl;
    }
    return res;
}


int main()
{
	int n,m;
	while(scanf("%d%d",&n,&m),n+m)
	{
		edgenum=0;
		int x1,y1,x2,y2,cos; 
		for(int i=1;i<=n;i++)
		{
			sum[0]=0;
			cin>>a[i];
	        a[i]++;
		    sum[i]=sum[i-1]+a[i];	
		}
		for(int i=1;i<=n;i++)
		{
			//<<hash(i,1)<<endl;
			add_edge(0,hash(i,1),0);
		}
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=a[i]-1;j++)//高等级到低等级为0 
			add_edge(hash(i,j+1),hash(i,j),0);
		}
	
		for(int i=1;i<=m;i++)//x1门课y1等级 
		{
			cin>>x1>>y1>>x2>>y2>>cos; 
			y1++;y2++;
			//cout<<hash(x1,y1)<<" "<<hash(x2,y2)<<endl;
			add_edge(hash(x1,y1),hash(x2,y2),cos);
		}
		//for(int i=1;i<=edgenum;i++)
		//cout<<edge[i].u<<" "<<edge[i].v<<" "<<edge[i].cost<<endl;
		int result=zhuliu(0,sum[n],edgenum,edge);//只用考虑这些边 
		cout<<result<<endl;
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值