Controlling Companies
控制公司
题目 有些公司是其他公司的部分拥有者,因为他们获得了其他公司发行的股票的一部分。例如,福特公司拥有马自达公司12%的股票。据说,如果至少满足了以下三个条件之一,公司A就可以控制公司B了:
- 公司A = 公司B。
- 公司A拥有大于50%的公司B的股票。
- 公司A控制K(K >= 1)个公司,记为C1, ..., CK,每个公司Ci拥有xi%的公司B的股票,并且x1+ .... + xK > 50%。(包括公司本来持有的股票)
给你一个表,每行包括三个数(i,j,p);表明公司i享有公司j的p%的股票。计算所有的数对(h,s),表明公司h控制公司s。至多有100个公司。
写一个程序读入N组数(i,j,p),i,j和p是都在范围(1..100)的正整数,并且找出所有的数对(h,s),使得公司h控制公司s。
输入格式
第一行: N,表明接下来三个数的数量,即(i,j,p)的数量。
第二行到第N+1行: 每行三个整数作为一个三对数(i,j,p),表示i公司拥有j公司 p%的股份。
样例输入 (file concom.in)
3 1 2 80 2 3 80 3 1 20
输出格式
输出零个或更多个的控制其他公司的公司。每行包括两个整数A、B,表示A公司控制了B公司。将输出的数对以升序排列。
请不要输出控制自己的公司(应该是不输出自己,互相控制的公司还是要输出的)。
样例输出 (file concom.out)
1 2 1 3 2 3
分析:
这道题刚开始自己看着还挺麻烦,不想写。不过仔细研究一下就发现是个很简单的搜索题。
设f[i][j]是i公司直接控j公司多少股,p[i][j]是i公司直接+间接控j公司多少股,h[i][j]表示i公司是否可以控制j公司。
首先把所有直接可以控制的关系添加进去,然后开始枚举更新所有公司的间接持股,没枚举完一次就判断是否添加了新控制关系,而每添加一组控制关系就要再把所有的关系更新一遍(看到这里我就突然想到了Dijkstra,每确定一个点都要松弛一次,然后恍然大悟,学算法不仅要理解表面,还要学习它里面包含的思想~~~)
代码:
/*
ID: 138_3531
PROB: concom
LANG: C++
*/
#include<iostream>
#include<fstream>
#include<cstring>
using namespace std;
int f[101][101],p[101][101];
char h[101][101];
int n;
ifstream fin("concom.in");
ofstream fout("concom.out");
int main()
{
int max=0;
fin>>n;
memset(h,0,sizeof(h));
memset(f,0,sizeof(f));
for (int i=0;i<n;i++)
{
int x,y;
fin>>x>>y;
if (x>max) max=x;
if (y>max) max=y;
fin>>f[x][y];
if (f[x][y]>50)
h[x][y]=1;
}
int ok=1;
while (ok)
{
ok=0;
memset(p,0,sizeof(p));
for (int i=1;i<=max;i++)
for (int j=1;j<=max;j++)
p[i][j]=f[i][j];
for (int i=1;i<=max;i++)
for (int j=1;j<=max;j++)
if (h[i][j])
for (int k=1;k<=max;k++)
p[i][k]+=f[j][k];
for (int i=1;i<=max;i++)
for (int j=1;j<=max;j++)
if ((p[i][j]>50)&&(h[i][j]==0))
{
h[i][j]=1;
ok=1;
}
}
for (int i=1;i<=max;i++)
for (int j=1;j<=max;j++)
if ((h[i][j])&&(i!=j))
fout<<i<<' '<<j<<endl;
return 0;
}