首页 > 代码库 > NOIP模拟赛-征兵

NOIP模拟赛-征兵

一个国王,他拥有一个国家。最近他因为国库里钱太多了,要征集一只部队要保卫国家。他选定了N个女兵和M个男兵,但事实上每征集一个兵他就要花10000RMB,即使国库里钱再多也伤不起啊。他发现,某男兵和某女兵之间有某种关系,这种关系可以使KING少花一些钱就可以征集到兵,不过国王也知道,在征兵的时候,每一个兵只能使用一种关系来少花钱。这时国王向你求助,问他最少要花多少的钱。

读入(conscription.in)

第一行:T,一共T组数据。

接下来T组数据,

第一行包括N,M,R

接下来的R行 包括Xi,Yi,Vi 表示如果招了第Xi个女兵,再招第Yi个男兵能省Vi元(同样表示如果招了第Yi个男兵,再招第Xi个女兵能也省Vi元)

输出(conscription.out)

共T行,表示每组数据的最终花费是多少(因为国库里的钱只有2^31-1,所以保证最终花费在maxlongint范围内)

 

这题是一道最小生成树的题 其实题目说的有点不太清楚 每个人只能用一种关系来少花钱 如果说一个人”被依赖“或”依赖别人“少花钱后这两人都不能利用关系了 这样的话很容易想到二分图匹配 写了半天最大流发现用二分图做也不会 而且数据太大 但题目的意思其实是每个人用”别人“来少花钱 而对方不受影响 那么一共有n+m个人 我们选n+m-1条边 也就是关系 因为第一个人被征用时没有人在队伍里 他不能利用任何关系 这样一来就是最小生成树 或者说最大生成树了 还要注意联通性问题 如果不连通 那么选不了n+m-1那么多条边 尽量多选就行了

 

技术分享
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<vector>
 4 #include<algorithm>
 5 #define LL long long
 6 using namespace std;
 7 const int maxn=20010;
 8 struct Edge{
 9     LL from,to,dist;
10     bool operator<(const Edge& rhs)const{
11         return dist<rhs.dist;
12     }
13 };
14 LL n,m,r,fa[maxn],x,y,z;
15 vector<Edge> edges; 
16 void init(){
17     for(int i=1;i<=n+m;i++) fa[i]=i;
18     edges.clear();
19 }
20 LL find(LL x){
21     if(fa[x]==x) return x;
22     return fa[x]=find(fa[x]);
23 }
24 int main(){
25     freopen("conscription.in","r",stdin);
26     freopen("conscription.out","w",stdout);
27     int T;
28     scanf("%d",&T);
29     while(T--){
30         scanf("%lld%lld%lld",&m,&n,&r);
31         init();
32         for(int i=1;i<=r;i++){
33             scanf("%lld%lld%lld",&x,&y,&z);
34             edges.push_back((Edge){m+x+1,y+1,-z});
35         }
36         sort(edges.begin(),edges.end());
37         LL ans=0;
38         for(int i=0;i<edges.size();i++){
39             Edge& e=edges[i];
40             LL a=find(e.from),b=find(e.to);
41             if(a==b) continue;
42             ans+=e.dist;
43             fa[a]=b;
44         }
45         printf("%lld\n",10000*(n+m)+ans);
46     }
47     fclose(stdin);
48     fclose(stdout);
49     return 0;
50 }
View Code

 

NOIP模拟赛-征兵