【2019.1.24】暴力&&权值&&邻接表 纪中C组T4——【东莞市选2008】医院

瓦不管瓦不管,反正我就是A了,而且思路貌似没有问题,数组开大点有什么关系呢。

题目

给出一个有向图G=(V,E),它表示某地一些城市的连接关系。由于要提供医疗服务,政府需要在某些城市中建设一些医院。但出于某些因素的考虑,作出如下限制:一个城市至多只能有一间医院,同时,两个相邻的城市也只能有一间医院。注意城市i与城市j相邻当且仅当G中存在一条有向边<i,j>或<j,i>。因此有些城市可能就不能建立医院了,这样,没有医院的城市的人们就会让有医院的城市派出医生为他们看病。当然人们都愿意选择离他们最近城市的医生过来,但如果离他们最近的城市都很远的话,病人们就会很不满意,因为这需要承担很多让医生过来的路费。这个不满意度是这样计算的:
S[i] = ( 离城市i最近的医院到城市i所经过的边数 / 3 ) * U
这里的i为某个没有医院的城市,U为某个常数,”/”为整除符号。你的任务是制订一套建设医院的方案,使得满足上述条件的约束下,所有城市的不满意度值之和最小。你要注意你的方案必须能让医院覆盖到所有的城市,即每个城市都至少有一个医院能出发到达。
例如下图有四个城市,连接关系如各边方向所示。假设U=10,如果我们只建立一个医院在城市4中,那么城市1的不满意度就为10,其余城市的不满意度为0。而一个不错的方案是建立医院在城市2与城市4中。

Input

输入第一行为两个整数N和M,分别表示城市数与边的数量。1<=N<=100,0<=M<=10000。
接下来M行,每行两个整数X和Y,1<=X,Y<=N,X≠Y,表示存在一条X到Y的有向边。
最后一行为一个整数U,为定义不满意度值中使用到的那个常数。

Output

输出包含三行,第一行为你找到的最小的不满意度值之和,第二行为你的方案建立的医院数量H,第三行有H个整数,为建立医院所在的城市,按城市编号由小到大排序。这样的方案可能不唯一,在保证不满意度值之和最小的情况下,输出任意一种均可。

思路

之前用另一个方法神奇RE,于是试着改了一下方法,一次AC。。。
因为题目说,有多种解法,而此题其实满意值肯定为0,所以输出0\n1\n1可以得到50分(无语地大笑着鼓掌)
邻接表:y存此路到达的地方,next存上一条路在数据结构的哪里,而l[i]为i点连接的最后一条边。

#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,t=0,T=0,l[101],L[101],p,ans,Ans[101]; //l和L辅助存边
bool B[101];
struct L{                      //定义数据结构,存边
	int y,next;
} k[10001],u[10001];
struct K{                    //定义数据结构,用于存d点的入度值z
	int d,z;
} rd[101];
void add(int a,int b){       //邻接表加边
	k[++t].y=b;
	k[t].next=l[a];
	l[a]=t;
}
void ad(int a,int b){       //邻接表加边
	u[++T].y=b;
	u[T].next=L[a];
	L[a]=T;
}
bool Q(K a,K b){
	return a.z<b.z;
}
int main(){
	freopen("d.in","r",stdin);
	freopen("d.out","w",stdout);
	scanf("%d%d",&n,&m);             //读入
	for(int i=1;i<=n;++i)
	  rd[i].d=i;
	for(register int i=1;i<=m;++i){
	    int a,b;
		scanf("%d%d",&a,&b);
		rd[b].z++;                  //rd.z为入度,rd.d存它是哪个点,因为等下要排序
		add(a,b);                  //a链接的点存下
		ad(b,a);                   //链接到b的点存下
	}
	sort(rd+1,rd+1+n,Q);          //入度排序
	for(int i=1;i<=n;++i)
	  if(!B[rd[i].d]){            //直接贪心(反正有多种解法,输出其中一种即可)
	  	p=rd[i].d;
	  	ans++;                    //保存结果
	  	Ans[ans]=p;
	  	for(int j=l[p];j;j=k[j].next) B[k[j].y]=true;   //把其相邻的边标记为不可以
	  	for(int j=L[p];j;j=u[j].next) B[u[j].y]=true;
	  }
	printf("0\n%d\n",ans);
	sort(Ans+1,Ans+1+ans);      //因为要求输出是从小到大的,所以排个序
	for(int i=1;i<=ans;++i)
	  printf("%d ",Ans[i]);
	fclose(stdin);
	fclose(stdout);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42937087/article/details/86651931