网络已经成为当今世界不可或缺的一部分。每天都有数以亿计的人使用网络 进行学习、科研、娱乐等活动。然而,不可忽视的一点就是网络本身有着庞大的 运行费用。所以,向使用网络的人进行适当的收费是必须的,也是合理的。
MY 市 NS 中学就有着这样一个教育网络。网络中的用户一共有 2N个,编号 依次为 1, 2, 3, …, 2N。这些用户之间是用路由点和网线组成的。用户、路由点与 网线共同构成一个满二叉树结构。树中的每一个叶子结点都是一个用户,每一个 非叶子结点(灰色)都是一个路由点,而每一条边都是一条网线(见下图,用户 结点中的数字为其编号)。
MY 网络公司的网络收费方式比较奇特,称为“ 配对收费 ”。即对于每两个 用户 i, j (1≤i < j ≤2N ) 进行收费。由于用户可以自行选择两种付费方式 A、B 中的一种,所以网络公司向学校收取的费用与每一位用户的付费方式有关。该费 用等于每两位不同用户配对产生费用之和。
为了描述方便,首先定义这棵网络树上的一些概念: 祖先:根结点没有祖先,非根结点的祖先包括它的父亲以及它的父亲的祖先; 管辖叶结点:叶结点本身不管辖任何叶结点,非叶结点管辖它的左儿子所管 辖的叶结点与它的右儿子所管辖的叶结点; 距离:在树上连接两个点之间的用边最少的路径所含的边数。
对于任两个用户 i, j (1≤i
由于最终所付费用与付费方式有关,所以 NS 中学的用户希望能够自行改变 自己的付费方式以减少总付费。然而,由于网络公司已经将每个用户注册时所选 择的付费方式记录在案,所以对于用户 i,如果他/她想改变付费方式(由 A 改为 B或由 B改为A),就必须支付Ci元给网络公司以修改档案(修改付费方式记录)。 现在的问题是,给定每个用户注册时所选择的付费方式以及 Ci,试求这些用 户应该如何选择自己的付费方式以使得 NS 中学支付给网络公司的总费用最少 (更改付费方式费用+配对收费的费用)。
输入描述
Input Description
输入文件中第一行有一个正整数 N。 第二行有 2N个整数,依次表示 1 号,2 号,…,2N号用户注册时的付费方式, 每一个数字若为 0,则表示对应用户的初始付费方式为 A,否则该数字为 1,表 示付费方式为 B。 第三行有 2N个整数,表示每一个用户修改付费方式需要支付的费用,依次为 C1, C2, …,CM 。( M=2N ) 以下 2N-1 行描述给定的两两用户之间的流量表 F,总第(i + 3)行第 j 列的整 数为 Fi, j+i 。(1≤i<2N,1≤j≤2N – i) 所有变量的含义可以参见题目描述。
输出描述
Output Description
你的程序只需要向输出文件输出一个整数,表示 NS 中学支付给网络公司的 最小总费用。(单位:元)
样例输入
Sample Input
2
1 0 1 0
2 2 10 9
10 1 2
2 1
3
数据范围及提示
Data Size & Hint
将 1 号用户的付费方式由 B 改为 A,NS 中学支付给网络公司的费用达到最 小。
40%的数据中 N≤4;
80%的数据中 N≤7;
100%的数据中 N≤10,0≤Fi, j≤500,0≤Ci≤500 000。
纯论文题,按照论文所说的做,并且加上记忆化搜索,很容易就AC了。小细节看注释。
1 #include
2 #define clr(x) memset(x,0,sizeof(x))
3 #define clr_1(x) memset(x,-1,sizeof(x))
4 #define clrmax(x) memset(x,0x3f3f3f3f,sizeof(x))
5 #define mod 1000000007
6 #define LL long long
7 using namespace std;
8 const int maxN=5e3+10;
9 int f[maxN][maxN];
10 int flow[maxN][maxN];
11 int c[maxN];
12 int cost[maxN][20],fa[maxN][20];
13 bool chose[maxN];
14 int N,n,m,k,ans,p;
15 int dfs(int u,int dep,int sta)//sta前从右往左第dep+1位开始是该结点分配的B方式的数量,1~dep位为其祖先结点na和nb的大小相对关系,表现为B收费为1,A收费为0。
16 {
17 if(f[u][sta]!=0x3f3f3f3f) return f[u][sta];
18 int num=sta>>dep;
19 int fasta=sta^(num<<dep);
20 //该结点的收费选择chos
21 int chos=(1<<(N-dep))-num>=num?1:0;
22 //叶子结点处理返回
23 if(dep==N)
24 {
25 int v=u-(n-1);
26 fasta<<=1;
27 fasta|=chos;
28 if(num^chose[v])
29 f[u][sta]=c[v];
30 else
31 f[u][sta]=0;
32 for(int i=N;i>=0;i--)
33 {
34 if(!((fasta&1)^num))
35 f[u][sta]+=cost[v][i];
36 fasta>>=1;
37 }
38 return f[u][sta];
39 }
40 //约束左右结点取B的数量在合理范围内,并选择其中最小的一个和。
41 int minx=max(0,num-(1<1));
42 int maxx=min(num,1<1);
43 for(int i=minx;i<=maxx;i++)
44 f[u][sta]=min(dfs(u<<1,dep+1,(i<1)|(fasta<<1|chos))+dfs(u<<1|1,dep+1,(num-i<1)|(fasta<<1|chos)),f[u][sta]);
45 return f[u][sta];
46 }
47 int main()
48 {
49 scanf("%d",&N);
50 n=1<<N;
51 for(int i=1;i<=n;i++)
52 {
53 scanf("%d",&p);
54 chose[i]=p;
55 }
56 for(int i=1;i<=n;i++)
57 scanf("%d",&c[i]);
58 for(int i=1;i<=n;i++)
59 for(int j=i+1;j<=n;j++)
60 scanf("%d",&flow[i][j]);
61 //计算子结点i(树上编号为i+n-1)在深度为j的祖先
62 for(int i=1;i<=n;i++)
63 {
64 k=i+n-1;
65 for(int j=N;j>=0;j--)
66 {
67 fa[i][j]=k;
68 k>>=1;
69 }
70 }
71 clr(cost);
72 //若i,j在深度为k处祖先相同,那末将流量费用flow[i,j]加到i和j在深度k所需要的费用中。
73 for(int i=1;i<=n;i++)
74 for(int j=i+1;j<=n;j++)
75 for(int k=N;k>=0;k--)
76 if(fa[i][k]==fa[j][k])
77 {
78 cost[i][k]+=flow[i][j];
79 cost[j][k]+=flow[i][j];
80 break;
81 }
82 clrmax(f);
83 ans=0x3f3f3f3f;
84 for(int i=0;i<=n;i++)
85 ans=min(ans,k=dfs(1,0,i));
86 printf("%d\n",ans);
87 return 0;
88 }
View Code
hdu 4276
The Ghost Blows Light
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3538 Accepted Submission(s): 1128
Problem Description
My name is Hu Bayi, robing an ancient tomb in Tibet. The tomb consists of N rooms (numbered from 1 to N) which are connected by some roads (pass each road should cost some time). There is exactly one route between any two rooms, and each room contains some treasures. Now I am located at the 1st room and the exit is located at the Nth room.
Suddenly, alert occurred! The tomb will topple down in T minutes, and I should reach exit room in T minutes. Human beings die in pursuit of wealth, and birds die in pursuit of food! Although it is life-threatening time, I also want to get treasure out as much as possible. Now I wonder the maximum number of treasures I can take out in T minutes.
Input
There are multiple test cases.
The first line contains two integer N and T. (1 <= n <= 100, 0 <= T <= 500)
Each of the next N - 1 lines contains three integers a, b, and t indicating there is a road between a and b which costs t minutes. (1<=a<=n, 1<=b<=n, a!=b, 0 <= t <= 100)
The last line contains N integers, which Ai indicating the number of treasure in the ith room. (0 <= Ai <= 100)
Output
For each test case, output an integer indicating the maximum number of treasures I can take out in T minutes; if I cannot get out of the tomb, please output "Human beings die in pursuit of wealth, and birds die in pursuit of food!".
Sample Input
5 10 1 2 2 2 3 2 2 5 3 3 4 3 1 2 3 4 5
Sample Output
如byteland的做法,多叉转二叉后对时间进行分配,分配给该结点的子树和他兄弟所在的子树。并记忆化搜索,时间效率还是很高的,比树上背包高那么一丢丢。
我们设置f[u][t]为从u点和其兄弟结点出发最终回到这些节点耗费时间t所能得到的最大财宝价值。所以f[u][t]=max {max{ f[left][k-time]+treasure[u]+f[right][k-u-time] } , f[right][t] },time为链向该点边的边权*2,left为该点孩子,right为该点兄弟。treasure[u]为宝藏价值即点权。k为对该部分分配的时间。
如果选择u所在的子树,则需要减去链向u的边的边权(时间*2),如果选择其兄弟结点则直接选择不需要减去边权(因为递归到兄弟结点,兄弟结点会自行选择是否选择他自己)。这样进行一个时间分配的dfs就能得出结果。但是由于我们一定要走1~n的路径,所以先把1~n的点权赋为0,边权赋为0,再做这个树形dp。
1 #include
2 #define clr(x) memset(x,0,sizeof(x))
3 #define clr_1(x) memset(x,-1,sizeof(x))
4 #define mod 1000000007
5 #define LL long long
6 using namespace std;
7 const int maxT=5e2+10;
8 const int maxN=1e2+10;
9 int f[maxN][maxT];
10 struct edg
11 {
12 int next,to,val;
13 }edge[maxN*2];
14 int head[maxN],ecnt;
15 void addedge(int u,int v,int val)
16 {
17 edge[++ecnt]=(edg){head[u],v,val};
18 head[u]=ecnt;
19 return ;
20 }
21 int n,t,tre[maxN],u,v,cost,alltre,flag;
22 bool dfs1(int u,int pre,int dist)
23 {
24 bool p=0,q;
25 if(u==n) p=1;
26 if(u==n && dist>t)
27 flag=-1;
28 if(u==n && dist<=t)
29 flag=dist;
30 if(head[u]!=-1 &&edge[head[u]].to==pre)
31 head[u]=edge[head[u]].next;
32 for(int i=head[u];i!=-1;i=edge[i].next)
33 {
34 if(edge[i].next!=-1 &&edge[edge[i].next].to==pre)
35 edge[i].next=edge[edge[i].next].next;
36 q=dfs1(edge[i].to,u,edge[i].val+dist);
37 if(q)
38 edge[i].val=0;
39 p|=q;
40 }
41 if(p)
42 {
43 alltre+=tre[u];
44 tre[u]=0;
45 }
46 return p;
47 }
48 int dfs2(int u,int t,int i)
49 {
50 if(f[u][t]!=-1) return f[u][t];
51 f[u][t]=0;
52 //只选兄弟
53 f[u][t]=max(f[u][t],edge[i].next==-1?0:dfs2(edge[edge[i].next].to,t,edge[i].next));
54 //选兄弟和自己的子树
55 int tt=t-2*edge[i].val;
56 if(tt>=0)
57 {
58 for(int j=0;j<=tt;j++)
59 f[u][t]=max(f[u][t],(head[u]==-1?0:dfs2(edge[head[u]].to,j,head[u]))+tre[u]+(edge[i].next==-1?0:dfs2(edge[edge[i].next].to,tt-j,edge[i].next)));
60 }
61 return f[u][t];
62 }
63 int main()
64 {
65 while(scanf("%d%d",&n,&t)!=EOF)
66 {
67 clr_1(head);
68 ecnt=0;
69 clr_1(f);
70 alltre=0;
71 for(int i=1;i)
72 {
73 scanf("%d%d%d",&u,&v,&cost);
74 addedge(u,v,cost);
75 addedge(v,u,cost);
76 }
77 for(int i=1;i<=n;i++)
78 scanf("%d",&tre[i]);
79 dfs1(1,1,0);
80 if(flag==-1)
81 {
82 printf("Human beings die in pursuit of wealth, and birds die in pursuit of food!\n");
83 continue;
84 }
85 edge[0].next=-1;
86 edge[0].val=0;
87 printf("%d\n",alltre+dfs2(1,t-flag,0));
88 }
89 return 0;
90 }
View Code
codeforces 219D
The country Treeland consists of n cities, some pairs of them are connected with unidirectional roads. Overall there are n - 1 roads in the country. We know that if we don't take the direction of the roads into consideration, we can get from any city to any other one.
The council of the elders has recently decided to choose the capital of Treeland. Of course it should be a city of this country. The council is supposed to meet in the capital and regularly move from the capital to other cities (at this stage nobody is thinking about getting back to the capital from these cities). For that reason if city a is chosen a capital, then all roads must be oriented so that if we move along them, we can get from city a to any other city. For that some roads may have to be inversed.
Help the elders to choose the capital so that they have to inverse the minimum number of roads in the country.
Output
In the first line print the minimum number of roads to be inversed if the capital is chosen optimally. In the second line print all possible ways to choose the capital — a sequence of indexes of cities in the increasing order.
Examples
output
2
1 2 3
emm算水题吧。先统计下以1为子树要改造多少条路才能做首都。然后对每个点做首都计算其相对于1的改造数量。我们可以发现,每个点为根和以1为根要改造的道路不同之处在于从根到这个点的路上的道路全取反。也就是在这条路上要改造的变为不改造,不改造的变为改造。因此每个点相对改造数量在一遍dfs的时候都能求出来,记录下来在f[i]中。以上两个步骤能在一个dfs中完成。然后查找f[i]中最小值加上1需要改造的道路数就是答案。
1 #include
2 #define clr(x) memset(x,0,sizeof(x))
3 #define clr_1(x) memset(x,-1,sizeof(x))
4 #define mod 1000000007
5 #define LL long long
6 using namespace std;
7 const int N=2e5+10;
8 struct edg
9 {
10 int next,to;
11 bool val;
12 }edge[N*2];
13 int head[N],ecnt,n,m,k,t,minx,u,v,all;
14 int f[N];
15 void addedge(int u,int v,bool val)
16 {
17 edge[++ecnt]=(edg){head[u],v,val};
18 head[u]=ecnt;
19 return ;
20 }
21 void init()
22 {
23 clr_1(head);
24 ecnt=0;
25 minx=0x3f3f3f3f;
26 all=0;
27 return ;
28 }
29 void dfs(int u,int pre,int val)
30 {
31 if(val<minx)
32 minx=val;
33 f[u]=val;
34 for(int i=head[u];i!=-1;i=edge[i].next)
35 if(pre!=edge[i].to)
36 {
37 if(!edge[i].val)
38 all++;
39 dfs(edge[i].to,u,edge[i].val?val+1:val-1);
40 }
41 return ;
42 }
43 int main()
44 {
45 scanf("%d",&n);
46 init();
47 for(int i=1;i)
48 {
49 scanf("%d%d",&u,&v);
50 addedge(u,v,true);
51 addedge(v,u,false);
52 }
53 dfs(1,1,0);
54 printf("%d\n",all+minx);
55 for(int i=1;i<=n;i++)
56 if(f[i]==minx)
57 printf("%d ",i);
58 printf("\n");
59 return 0;
60 }
View Code
poj 3107
Godfather
Time Limit: 2000MS |
|
Memory Limit: 65536K |
Total Submissions: 7627 |
|
Accepted: 2691 |
Description
Last years Chicago was full of gangster fights and strange murders. The chief of the police got really tired of all these crimes, and decided to arrest the mafia leaders.
Unfortunately, the structure of Chicago mafia is rather complicated. There are n persons known to be related to mafia. The police have traced their activity for some time, and know that some of them are communicating with each other. Based on the data collected, the chief of the police suggests that the mafia hierarchy can be represented as a tree. The head of the mafia, Godfather, is the root of the tree, and if some person is represented by a node in the tree, its direct subordinates are represented by the children of that node. For the purpose of conspiracy the gangsters only communicate with their direct subordinates and their direct master.
Unfortunately, though the police know gangsters’ communications, they do not know who is a master in any pair of communicating persons. Thus they only have an undirected tree of communications, and do not know who Godfather is.
Based on the idea that Godfather wants to have the most possible control over mafia, the chief of the police has made a suggestion that Godfather is such a person that after deleting it from the communications tree the size of the largest remaining connected component is as small as possible. Help the police to find all potential Godfathers and they will arrest them.
Input
The first line of the input file contains n — the number of persons suspected to belong to mafia (2 ≤ n ≤ 50 000). Let them be numbered from 1 to n.
The following n − 1 lines contain two integer numbers each. The pair ai, bi means that the gangster ai has communicated with the gangster bi. It is guaranteed that the gangsters’ communications form a tree.
Output
Print the numbers of all persons that are suspected to be Godfather. The numbers must be printed in the increasing order, separated by spaces.
Sample Input
6
1 2
2 3
2 5
3 4
3 6
Sample Output
2 3
求结点u为根的树中,它的子节点的子树中结点数量最大的最小的,并输出这样的结点u。水题,无需赘言。
1 //#include
2 #include
3 #include
4 #include
5 #include
6 #define clr(x) memset(x,0,sizeof(x))
7 #define clr_1(x) memset(x,-1,sizeof(x))
8 #define mod 1000000007
9 #define LL long long
10 using namespace std;
11 const int N=2e5+10;
12 struct edg
13 {
14 int next,to;
15 }edge[N*2];
16 int head[N],ecnt,n,m,k,t,u,v,rmin;
17 int f[N],son[N];
18 void addedge(int u,int v)
19 {
20 edge[++ecnt]=(edg){head[u],v};
21 head[u]=ecnt;
22 return ;
23 }
24 void init()
25 {
26 clr_1(head);
27 ecnt=0;
28 rmin=0x3f3f3f3f;
29 return ;
30 }
31 void dfs(int u,int pre)
32 {
33 int minx=0;
34 son[u]=1;
35 for(int i=head[u];i!=-1;i=edge[i].next)
36 if(pre!=edge[i].to)
37 {
38 dfs(edge[i].to,u);
39 son[u]+=son[edge[i].to];
40 minx=max(son[edge[i].to],minx);
41 }
42 minx=max(minx,n-son[u]);
43 f[u]=minx;
44 rmin=min(rmin,minx);
45 return ;
46 }
47 int main()
48 {
49 scanf("%d",&n);
50 init();
51 for(int i=1;i)
52 {
53 scanf("%d%d",&u,&v);
54 addedge(u,v);
55 addedge(v,u);
56 }
57 dfs(1,1);
58 for(int i=1;i<=n;i++)
59 if(f[i]==rmin)
60 printf("%d ",i);
61 printf("\n");
62 return 0;
63 }
View Code
poj 3140
Contestants Division
Time Limit: 2000MS |
|
Memory Limit: 65536K |
Total Submissions: 10726 |
|
Accepted: 3012 |
Description
In the new ACM-ICPC Regional Contest, a special monitoring and submitting system will be set up, and students will be able to compete at their own universities. However there’s one problem. Due to the high cost of the new judging system, the organizing committee can only afford to set the system up such that there will be only one way to transfer information from one university to another without passing the same university twice. The contestants will be divided into two connected regions, and the difference between the total numbers of students from two regions should be minimized. Can you help the juries to find the minimum difference?
Input
There are multiple test cases in the input file. Each test case starts with two integers N and M, (1 ≤ N ≤ 100000, 1 ≤ M ≤ 1000000), the number of universities and the number of direct communication line set up by the committee, respectively. Universities are numbered from 1 to N. The next line has N integers, the Kth integer is equal to the number of students in university numbered K. The number of students in any university does not exceed 100000000. Each of the following M lines has two integers s, t, and describes a communication line connecting university s and university t. All communication lines of this new system are bidirectional.
N = 0, M = 0 indicates the end of input and should not be processed by your program.
Output
For every test case, output one integer, the minimum absolute difference of students between two regions in the format as indicated in the sample output.
Sample Input
7 6
1 1 1 1 1 1 1
1 2
2 7
3 7
4 6
6 2
5 7
0 0
Sample Output
Case 1: 1
emmm水题。
1 //#include
2 #include
3 #include
4 #include
5 #include
6 #define clr(x) memset(x,0,sizeof(x))
7 #define clr_1(x) memset(x,-1,sizeof(x))
8 #define mod 1000000007
9 #define LL long long
10 using namespace std;
11 const int N=1e5+10;
12 struct edg
13 {
14 int next,to;
15 }edge[N*2];
16 int head[N],ecnt,n,m,k,t,u,v,pos;
17 LL all,rmin;
18 LL stu[N],son[N],f[N];
19 inline LL labs(LL x)
20 {
21 return x<0?-x:x;
22 }
23 void addedge(int u,int v)
24 {
25 edge[++ecnt]=(edg){head[u],v};
26 head[u]=ecnt;
27 return ;
28 }
29 void init()
30 {
31 clr_1(head);
32 ecnt=0;
33 all=0;
34 rmin=1e17;
35 return ;
36 }
37 void dfs(int u,int pre)
38 {
39 son[u]=stu[u];
40 for(int i=head[u];i!=-1;i=edge[i].next)
41 if(pre!=edge[i].to)
42 {
43 dfs(edge[i].to,u);
44 son[u]+=son[edge[i].to];
45 }
46 f[u]=labs(all-son[u]-son[u]);
47 if(f[u]<rmin)
48 rmin=f[u];
49 return ;
50 }
51 int main()
52 {
53 int kase=0;
54 while(scanf("%d%d",&n,&m) && n||m)
55 {
56 init();
57 for(int i=1;i<=n;i++)
58 {
59 scanf("%lld",&stu[i]);
60 all+=stu[i];
61 }
62 for(int i=1;i<=m;i++)
63 {
64 scanf("%d%d",&u,&v);
65 addedge(u,v);
66 addedge(v,u);
67 }
68 dfs(1,1);
69 printf("Case %d: %lld\n",++kase,rmin);
70 }
71 return 0;
72 }
View Code
poj 2378
Tree Cutting
Time Limit: 1000MS |
|
Memory Limit: 65536K |
Total Submissions: 4846 |
|
Accepted: 2965 |
Description
After Farmer John realized that Bessie had installed a "tree-shaped" network among his N (1 <= N <= 10,000) barns at an incredible cost, he sued Bessie to mitigate his losses.
Bessie, feeling vindictive, decided to sabotage Farmer John's network by cutting power to one of the barns (thereby disrupting all the connections involving that barn). When Bessie does this, it breaks the network into smaller pieces, each of which retains full connectivity within itself. In order to be as disruptive as possible, Bessie wants to make sure that each of these pieces connects together no more than half the barns on FJ.
Please help Bessie determine all of the barns that would be suitable to disconnect.
Input
* Line 1: A single integer, N. The barns are numbered 1..N.
* Lines 2..N: Each line contains two integers X and Y and represents a connection between barns X and Y.
Output
* Lines 1..?: Each line contains a single integer, the number (from 1..N) of a barn whose removal splits the network into pieces each having at most half the original number of barns. Output the barns in increasing numerical order. If there are no suitable barns, the output should be a single line containing the word "NONE".
Sample Input
10
1 2
2 3
3 4
4 5
6 7
7 8
8 9
9 10
3 8
Sample Output
3
8
水题。
1 //#include
2 #include
3 #include
4 #include
5 #define clr(x) memset(x,0,sizeof(x))
6 #define clr_1(x) memset(x,-1,sizeof(x))
7 #define LL long long
8 #define mod 1000000007
9 using namespace std;
10 const int N=1e4+10;
11 struct edg
12 {
13 int next,to;
14 }edge[2*N];
15 int head[N],ecnt,sonnum[N];
16 bool flag[N];
17 int n,m,t,u,v;
18 void addedge(int u,int v)
19 {
20 edge[++ecnt]=(edg){head[u],v};
21 head[u]=ecnt;
22 return ;
23 }
24 void init()
25 {
26 clr_1(head);
27 ecnt=-1;
28 return ;
29 }
30 void dfs(int u,int pre)
31 {
32 sonnum[u]=1;
33 bool p=1;
34 for(int i=head[u];i!=-1;i=edge[i].next)
35 if(edge[i].to!=pre)
36 {
37 dfs(edge[i].to,u);
38 if(sonnum[edge[i].to]>t)
39 p=0;
40 sonnum[u]+=sonnum[edge[i].to];
41 }
42 if(n-sonnum[u]>t)
43 p=0;
44 flag[u]=p;
45 return ;
46 }
47 int main()
48 {
49 scanf("%d",&n);
50 init();
51 for(int i=2;i<=n;i++)
52 {
53 scanf("%d%d",&u,&v);
54 addedge(u,v);
55 addedge(v,u);
56 }
57 t=n/2;
58 clr(flag);
59 dfs(1,1);
60 for(int i=1;i<=n;i++)
61 {
62 if(flag[i])
63 printf("%d\n",i);
64 }
65 return 0;
66 }
View Code
hdu 3586
Information Disturbing
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)
Total Submission(s): 3244 Accepted Submission(s): 1150
Problem Description
In the battlefield , an effective way to defeat enemies is to break their communication system.
The information department told you that there are n enemy soldiers and their network which have n-1 communication routes can cover all of their soldiers. Information can exchange between any two soldiers by the communication routes. The number 1 soldier is the total commander and other soldiers who have only one neighbour is the frontline soldier.
Your boss zzn ordered you to cut off some routes to make any frontline soldiers in the network cannot reflect the information they collect from the battlefield to the total commander( number 1 soldier).
There is a kind of device who can choose some routes to cut off . But the cost (w) of any route you choose to cut off can’t be more than the device’s upper limit power. And the sum of the cost can’t be more than the device’s life m.
Now please minimize the upper limit power of your device to finish your task.
Input
The input consists of several test cases.
The first line of each test case contains 2 integers: n(n<=1000)m(m<=1000000).
Each of the following N-1 lines is of the form:
ai bi wi
It means there’s one route from ai to bi(undirected) and it takes wi cost to cut off the route with the device.
(1<=ai,bi<=n,1<=wi<=1000)
The input ends with n=m=0.
Output
Each case should output one integer, the minimal possible upper limit power of your device to finish your task.
If there is no way to finish the task, output -1.
Sample Input
5 5 1 3 2 1 4 3 3 5 5 4 2 6 0 0
Sample Output
这题的话看到数据范围是n,wi<=1k,那么你心里就应该有点B数了。
对于每个结点我们求出所有切割最大值为p(1≤p≤max(wi))时,其最小的花费。具体为:minx(u,p)=Σminx(v,p)(p=cost),,其中cost为切掉u和他父结点之间的边的花费,v为其子节点。这样最多n*max(wi)<=100w的时间复杂度和空间复杂度。其中不存在该最小值的情况置一个大数。然后1号节点中找一个最小符合minx(u,p)<=m的,p即为答案。
1 //#include
2 #include
3 #include
4 #include
5 #define clr(x) memset(x,0,sizeof(x))
6 #define clr_1(x) memset(x,-1,sizeof(x))
7 #define LL long long
8 #define mod 1000000007
9 using namespace std;
10 const int N=1e3+10;
11 struct edg
12 {
13 int next,to,val;
14 }edge[2*N];
15 int head[N],ecnt;
16 LL minx[N][N];
17 int n,m,t,u,v,maxn;
18 void addedge(int u,int v,int val)
19 {
20 edge[++ecnt]=(edg){head[u],v,val};
21 head[u]=ecnt;
22 return ;
23 }
24 void init()
25 {
26 clr_1(head);
27 ecnt=-1;
28 return ;
29 }
30 void dfs(int u,int pre,int cost)
31 {
32 int p;
33 if(edge[head[u]].next==-1 && edge[head[u]].to==pre)
34 for(int i=1;i<=maxn;i++)
35 minx[u][i]=0x3f3f3f3f;
36 else
37 for(int i=1;i<=maxn;i++)
38 minx[u][i]=0;
39 for(int i=head[u];i!=-1;i=edge[i].next)
40 {
41 p=edge[i].to;
42 if(p!=pre)
43 {
44 dfs(p,u,edge[i].val);
45 for(int j=1;j<=maxn;j++)
46 minx[u][j]+=minx[p][j];
47 }
48 }
49 for(int i=cost;i<=maxn;i++)
50 minx[u][i]=min(minx[u][i],(LL)cost);
51
52 }
53 int flag;
54 int main()
55 {
56 while(scanf("%d%d",&n,&m)!=EOF && (n || m))
57 {
58 init();
59 maxn=0;
60 for(int i=2;i<=n;i++)
61 {
62 scanf("%d%d%d",&u,&v,&t);
63 addedge(u,v,t);
64 addedge(v,u,t);
65 maxn=max(maxn,t);
66 }
67 dfs(1,1,0x3f3f3f3f);
68 flag=0;
69 for(int i=1;i<=maxn;i++)
70 if(minx[1][i]<=(LL)m)
71 {
72 printf("%d\n",i);
73 flag=1;
74 break;
75 }
76 if(!flag)
77 printf("-1\n");
78 }
79 return 0;
80 }
View Code
Walking Race
Time Limit: 10000MS |
|
Memory Limit: 131072K |
Total Submissions: 4217 |
|
Accepted: 1047 |
Case Time Limit: 3000MS |
Description
flymouse’s sister wc is very capable at sports and her favorite event is walking race. Chasing after the championship in an important competition, she comes to a training center to attend a training course. The center has N check-points numbered 1 through N. Some pairs of check-points are directly connected by two-way paths. The check-points and the paths form exactly a tree-like structure. The course lasts Ndays. On the i-th day, wc picks check-point i as the starting point and chooses another check-point as the finishing point and walks along the only simple path between the two points for the day’s training. Her choice of finishing point will make it that the resulting path will be the longest among those of all possible choices.
After every day’s training, flymouse will do a physical examination from which data will obtained and analyzed to help wc’s future training be better instructed. In order to make the results reliable, flymouse is not using data all from N days for analysis. flymouse’s model for analysis requires data from a series of consecutive days during which the difference between the longest and the shortest distances wc walks cannot exceed a bound M. The longer the series is, the more accurate the results are. flymouse wants to know the number of days in such a longest series. Can you do the job for him?
Input
The input contains a single test case. The test case starts with a line containing the integers N (N ≤ 106) and M (M < 109). Then follow N − 1 lines, each containing two integers fi and di (i = 1, 2, …, N − 1), meaning the check-points i + 1 and fi are connected by a path of length di.
Output
Output one line with only the desired number of days in the longest series.
Sample Input
3 2
1 1
1 3
Sample Output
3
Hint
Explanation for the sample:
There are three check-points. Two paths of lengths 1 and 3 connect check-points 2 and 3 to check-point 1. The three paths along with wc walks are 1-3, 2-1-3 and 3-1-2. And their lengths are 3, 4 and 4. Therefore data from all three days can be used for analysis.
树形dp参考computer的解法,求的是每个点距离他最远的树上距离。然后对于求出来的答案len[i],用单调队列维护最大值和最小值,即尺取法解决。来找对应的右端点i能取到的最小的左端点j。然后取最大的(i-j+1)即为答案。
1 #include
2 #include
3 #include
4 #define clr(x) memset(x,0,sizeof(x))
5 #define clr_1(x) memset(x,-1,sizeof(x))
6 #define LL long long
7 #define mod 1000000007
8 using namespace std;
9 const int N=1e6+10;
10 struct edg
11 {
12 int next,to;
13 LL val;
14 }edge[N*2];
15 int head[N],ecnt;
16 LL maxn[N][3];
17 int pt[N];
18 int n,p,u,v;
19 LL len[N];
20 LL t,m;
21 struct que
22 {
23 int fpt,ept;
24 int es[N];
25 void init()
26 {
27 fpt=0;
28 ept=0;
29 return ;
30 }
31 void pop()
32 {
33 fpt++;
34 return ;
35 }
36 void popback()
37 {
38 ept--;
39 return ;
40 }
41 void push(int x)
42 {
43 es[ept++]=x;
44 return ;
45 }
46 int front( )
47 {
48 return es[fpt];
49 }
50 int back( )
51 {
52 return es[ept-1];
53 }
54 bool empty( )
55 {
56 return fpt==ept;
57 }
58 }minx,maxx;
59 int fminx,fmaxx,maxlong;
60 void dfs1(int u,int pre)
61 {
62 maxn[u][1]=maxn[u][2]=0;
63 for(int i=head[u];i!=-1;i=edge[i].next)
64 if(pre!=edge[i].to)
65 {
66 dfs1(edge[i].to,u);
67 if(maxn[edge[i].to][1]+edge[i].val>maxn[u][1])
68 {
69 pt[u]=edge[i].to;
70 maxn[u][1]=maxn[edge[i].to][1]+edge[i].val;
71 }
72 }
73 for(int i=head[u];i!=-1;i=edge[i].next)
74 if(pre!=edge[i].to && pt[u]!=edge[i].to)
75 {
76 if(maxn[edge[i].to][1]+edge[i].val>maxn[u][2])
77 {
78 maxn[u][2]=maxn[edge[i].to][1]+edge[i].val;
79 }
80 }
81 return ;
82 }
83 void dfs2(int u,int pre,LL maxfa)
84 {
85 len[u]=max(maxfa,maxn[u][1]);
86 for(int i=head[u];i!=-1;i=edge[i].next)
87 if(pre!=edge[i].to)
88 if(edge[i].to==pt[u])
89 dfs2(edge[i].to,u,max(maxn[u][2],maxfa)+edge[i].val);
90 else
91 dfs2(edge[i].to,u,max(maxn[u][1],maxfa)+edge[i].val);
92 }
93 void addedge(int u,int v,LL val)
94 {
95 edge[++ecnt]=(edg){head[u],v,val};
96 head[u]=ecnt;
97 return ;
98 }
99 int main()
100 {
101 scanf("%d%lld",&n,&m);
102 clr_1(head);
103 ecnt=0;
104 for(int i=2;i<=n;i++)
105 {
106 scanf("%d%lld",&v,&t);
107 addedge(i,v,t);
108 addedge(v,i,t);
109 }
110 dfs1(1,1);
111 dfs2(1,1,0);
112 // for(int i=1;i<=n;i++)
113 // printf("%d:%lld,%lld,%lld\n",i,len[i],maxn[i][1],maxn[i][2]);
114 // printf("\n");
115 maxlong=0;
116 minx.init();
117 maxx.init();
118 fminx=fmaxx=0;
119 for(int i=1;i<=n;i++)
120 {
121 while(!minx.empty() && len[minx.back()]>len[i])
122 minx.popback();
123 minx.push(i);
124 while(!maxx.empty() && len[maxx.back()]<len[i])
125 maxx.popback();
126 maxx.push(i);
127 while(!minx.empty() && !maxx.empty() && (len[maxx.front()]-len[minx.front()]>m))
128 if(maxx.front()>=minx.front())
129 {
130 fminx=minx.front();
131 minx.pop();
132 }
133 else
134 {
135 fmaxx=maxx.front();
136 maxx.pop();
137 }
138 // for(int i=minx.fpt;i139 // printf("%d ",minx.es[i]);
140 // printf("\n");
141 // for(int i=maxx.fpt;i142 // printf("%d ",maxx.es[i]);
143 // printf("\n");
144 // printf("%d %d %d\n",fminx,fmaxx,i-max(fminx,fmaxx));
145 maxlong=max(i-max(fminx,fmaxx),maxlong);
146 }
147 printf("%d\n",maxlong);
148 return 0;
149 }
View Code
hdu 5834
Magic boy Bi Luo with his excited tree
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1485 Accepted Submission(s): 452
Problem Description
Bi Luo is a magic boy, he also has a migic tree, the tree has
N nodes , in each node , there is a treasure, it's value is V[i], and for each edge, there is a cost C[i], which means every time you pass the edge i , you need to pay C[i].
You may attention that every V[i] can be taken only once, but for some C[i] , you may cost severial times.
Now, Bi Luo define ans[i] as the most value can Bi Luo gets if Bi Luo starts at node i.
Bi Luo is also an excited boy, now he wants to know every ans[i], can you help him?
Input
First line is a positive integer
T(T≤104) , represents there are T test cases.
Four each test:
The first line contain an integer N(N≤105).
The next line contains N integers V[i], which means the treasure’s value of node i(1≤V[i]≤104).
For the next N−1 lines, each contains three integers u,v,c , which means node u and node v are connected by an edge, it's cost is c(1≤c≤104).
You can assume that the sum of N will not exceed 106.
Output
For the i-th test case , first output Case #i: in a single line , then output
N lines , for the i-th line , output ans[i] in a single line.
Sample Input
1 5 4 1 7 7 7 1 2 6 1 3 1 2 4 8 3 5 2
Sample Output
题解来自:http://www.cnblogs.com/tun117/p/5834536.html
题意:n个点组成的树,点和边都有权值,当第一次访问某个点的时候获得利益为点的权值
每次经过一条边,丢失利益为边的权值。问从第i个点出发,获得的利益最大是多少。
输入:
测试样例组数T
n
n个数每个点的权值
n-1条无向边 a b c a和b是点的标号,c是边的权值。
思路:
注意题目只强调是从某个点出发,并不一定要回到该点。
考虑树形DP。
先随便定义一个树根。然后对于某个点,我们需要维护它子树方向的两个值
1.从该点出发,最终要回到该点的利益的最大值
2.从该点出发,最终不必回到该点的利益的最大值,以及最后一次从该点出发的是哪个儿子节点。
3.从该点出发,最终不必回到该点的利益的第二大值,以及最后一次从该点出发的是哪个儿子节点。
先求出回到该点的利益的最大值,然后枚举它的儿子节点,作为最后出去的节点,即该节点不返回。
第二和第三个值把枚举所有儿子作为最后一次出发的情况然后排序记录下前两个就可以了。
以上是第一次DFS所做的工作。
然后对于每个点维护三个值,进行第二次DFS。
1.从该点出发所有方向(子树方向和父亲方向)回到该点的利益的最大值。
2.从该点出发所有方向,不必回到该点的利益的最大值,并保存最后一个出发的儿子节点的标号。
3.从该点出发所有方向,不必回到该点的利益的第二大值,并保存最后一个出发的儿子节点的标号。
第1个值的维护只需要将子树方向和减掉本身所在子树所影响的父亲方向的值加起来即可。
对于第二个和第三个值,我们可以将子树方向上最大的两个值加上父亲方向回来所带来的利益,与
父亲方向作为最后一次出发的点不回来的利益这三个值中求取两个最大的即可。
之所以要维护第二大的值,是因为当父亲节点最终的答案(即可以不回来)的最后一次访问的点恰
好是我们要求取的它的儿子节点的时候,我们可以用次大的值来确定当该儿子节点的父亲方向作为
最后一次访问的方向的时候的利益。
最后所有的ans[i][1]就是答案。
1 #include
2 #include
3 #include
4 #include
5 #define clr(x) memset(x,0,sizeof(x))
6 #define clr_1(x) memset(x,-1,sizeof(x))
7 #define LL long long
8 #define mod 1000000007
9 using namespace std;
10 const int N=1e5+10;
11 struct edg
12 {
13 int next,to;
14 LL val;
15 }edge[N*2];
16 int head[N],ecnt;
17 void addedge(int u,int v,LL val)
18 {
19 edge[++ecnt]=(edg){head[u],v,val};
20 head[u]=ecnt;
21 return ;
22 }
23 LL allans[N][2],ans[N][2],allf[N],f[N],cpt[5],ct[5];
24 int dir[5],pt[N][2],allpt[N][2];
25 int n,m,t,T,u,vv;
26 LL v[N];
27 LL p;
28 bool cmp(int a,int b)
29 {
30 return ct[a]>ct[b];
31 }
32 void dfs1(int u,int pre)
33 {
34 f[u]=v[u];
35 pt[u][0]=pt[u][1]=u;
36 for(int i=head[u];i!=-1;i=edge[i].next)
37 {
38 if(edge[i].to!=pre)
39 {
40 dfs1(edge[i].to,u);
41 f[u]=max(f[u],f[u]+f[edge[i].to]-2*edge[i].val);
42 }
43 }
44 ans[u][0]=ans[u][1]=f[u];
45 for(int i=head[u];i!=-1;i=edge[i].next)
46 if(edge[i].to!=pre)
47 if(f[edge[i].to]-2*edge[i].val<=0)
48 {
49 if(ans[u][0]0]-edge[i].val)
50 {
51 ans[u][0]=f[u]+ans[edge[i].to][0]-edge[i].val;
52 pt[u][0]=edge[i].to;
53 }
54 }
55 else
56 {
57 if(ans[u][0]0]-f[edge[i].to]+edge[i].val)
58 {
59 ans[u][0]=f[u]+ans[edge[i].to][0]-f[edge[i].to]+edge[i].val;
60 pt[u][0]=edge[i].to;
61 }
62 }
63 for(int i=head[u];i!=-1;i=edge[i].next)
64 if(edge[i].to!=pre && edge[i].to!=pt[u][0])
65 if(f[edge[i].to]-2*edge[i].val<=0)
66 {
67 if(ans[u][1]0]-edge[i].val)
68 {
69 ans[u][1]=f[u]+ans[edge[i].to][0]-edge[i].val;
70 pt[u][1]=edge[i].to;
71 }
72 }
73 else
74 {
75 if(ans[u][1]0]-f[edge[i].to]+edge[i].val)
76 {
77 ans[u][1]=f[u]+ans[edge[i].to][0]-f[edge[i].to]+edge[i].val;
78 pt[u][1]=edge[i].to;
79 }
80 }
81 return ;
82 }
83 void dfs2(int u,int pre,LL cost)
84 {
85 LL k=(f[u]-2*cost)>0?(allf[pre]-f[u]+2*cost):allf[pre];
86 allf[u]=max(f[u],f[u]+k-2*cost);
87 ct[0]=max(ans[u][0]+k-2*cost,ans[u][0]);
88 cpt[0]=pt[u][0];
89 ct[1]=max(ans[u][1]+k-2*cost,ans[u][1]);
90 cpt[1]=pt[u][1];
91 k=(f[u]-2*cost>0)?(f[u]-2*cost):0;
92 ct[2]= f[u]+((allpt[pre][0]==u)?(allans[pre][1]-k):(allans[pre][0]-k))-cost;
93 cpt[2]=pre;
94 ct[3]=allf[u];
95 cpt[3]=u;
96 ct[4]=allf[u];
97 cpt[4]=u;
98 for(int i=0;i<5;i++)
99 dir[i]=i;
100 sort(dir,dir+5,cmp);
101 for(int i=0;i<2;i++)
102 {
103 allans[u][i]=ct[dir[i]];
104 allpt[u][i]=cpt[dir[i]];
105 }
106 for(int i=head[u];i!=-1;i=edge[i].next)
107 if(edge[i].to!=pre)
108 dfs2(edge[i].to,u,edge[i].val);
109 return ;
110 }
111 int main()
112 {
113 scanf("%d",&T);
114 for(int kase=1;kase<=T;kase++)
115 {
116 scanf("%d",&n);
117 for(int i=1;i<=n;i++)
118 {
119 scanf("%lld",&v[i]);
120 }
121 for(int i=1;i<=n;i++)
122 head[i]=-1;
123 ecnt=0;
124 for(int i=2;i<=n;i++)
125 {
126 scanf("%d%d%lld",&u,&vv,&p);
127 addedge(u,vv,p);
128 addedge(vv,u,p);
129 }
130 dfs1(1,1);
131 allf[1]=f[1];
132 allans[1][0]=ans[1][0];
133 allpt[1][0]=pt[1][0];
134 allans[1][1]=ans[1][1];
135 allpt[1][1]=pt[1][1];
136 for(int i=head[1];i!=-1;i=edge[i].next)
137 dfs2(edge[i].to,1,edge[i].val);
138 printf("Case #%d:\n",kase);
139 for(int i=1;i<=n;i++)
140 printf("%lld\n",allans[i][0]);
141 }
142 return 0;
143 }
View Code