首页 > 代码库 > hdu 2121 Ice_cream’s world II

hdu 2121 Ice_cream’s world II

真的是一下午都砸在这题上了

不对 是从上午10点到现在都砸掉了

啊啊啊啊啊啊啊啊我有毒吧!!!!!!!

我真的是不想再看到这道题了 卡了电脑3遍啊啊啊啊啊为什么!!!!!

生无可恋脸

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<string>
 7 #define maxm 10010
 8 #define inf 0x7f7f7f7f 
 9 using namespace std;
10 int n,m,cnt,sum,mr,tot,rec;
11 struct hh{
12     int u,v,d;
13 }b[maxm*3];
14 int in[maxm],pre[maxm],col[maxm],id[maxm];
15 int zl(int root,int p){
16     rec=0;//一定 !!!不能!!!!定义到!!!!里面去!!!!!!
17     while (1){
18         for (int i=0;i<=p;++i) in[i]=inf;
19         memset(pre,-1,sizeof(pre));//可能涉及到零 所以每个数组都初始化为-1
20         for (int i=1;i<=cnt;++i){
21             int x=b[i].u,y=b[i].v,z=b[i].d;
22             if (z<in[y]&&x!=y){
23                 pre[y]=x;
24                 in[y]=z;
25                 if (x==root) mr=i;
26             }
27         }
28         tot=0;
29         memset(id,-1,sizeof(id));
30         memset(col,-1,sizeof(col));
31         in[root]=0;
32         for (int i=0;i<=p;++i){
33             rec+=in[i];
34             int j=i;
35             while (j!=root&&col[j]!=i&&id[j]==-1) col[j]=i,j=pre[j];
36             if (j!=root&&id[j]==-1){
37                 for (int q=pre[j];q!=j;q=pre[q]) id[q]=tot;
38                 id[j]=tot++;
39             }
40         }
41         if (tot==0) break;
42         for (int i=0;i<=p;++i) if (id[i]==-1) id[i]=tot++;
43         for (int i=1;i<=cnt;++i){
44             int x=b[i].u,y=b[i].v;
45             b[i].u=id[x];
46             b[i].v=id[y];
47             if (b[i].u!=b[i].v) b[i].d-=in[y];
48         }
49         p=tot-1;
50         root=id[root];
51     }
52     return rec;
53 }
54 int main(){
55     while (scanf ("%d%d",&n,&m)!=EOF){
56         memset(b,-1,sizeof(b));
57         cnt=0,sum=0;
58         for (int i=1;i<=m;++i){
59             int x,y,z;
60             scanf ("%d%d%d",&x,&y,&z);
61             b[++cnt].u=x+1,b[cnt].v=y+1,b[cnt].d=z;
62             sum+=z;
63         }
64         sum++;
65         for (int i=1;i<=n;++i) b[++cnt].u=0,b[cnt].v=i,b[cnt].d=sum;
66         int ans=zl(0,n);
67         if (ans>=2*sum) printf("impossible\n\n");
68         else printf("%d %d\n\n",ans-sum,mr-m-1);
69     }
70     return 0;
71   }

学过的人都知道是朱刘算法 如果没有了解的话推荐blog http://blog.csdn.net/l123012013048/article/details/48375819

以及度娘也讲得比较清楚 如果光看解释看不懂 还是应该多写写画画 再跟着代码理解一下

这里就不赘述了其实我也并不怎么太懂

解释下几个关键点

1.这题出来之后很容易就发现 它跟正常求最小生成树有一点很重要的不同 ——没有固定的根 

那这就很尴尬了 但是自己动手丰衣足食 没有根的话大不了造一个吧

好 那就造一个0 并且把他跟图里的所有点都连下边吧(注意!原题中可能出现编号为0的点 为了不冲突 输入时进行加1操作(结束输出时会-1

2.然后这个点我们连边的时候权值是sum+1 因为如果它只给你点而不给你边的时候是无法把这种不合法情况判出来的!

记住 这个时候 sum已经加1了!

3.接着就是板子式的zl算法 出来之后————————!!!

判impossible的时候到了! 接下来我们可以用到之前的sum了 因为图中应该只有一个入度为0即直连虚根的点所以 ans最大不会超过sum(已加1)*2

好的 这题就写完了qwq 反正我是挂在把rec定义到了while里面所以狂wa5遍QAQ

这应该是我写过最神经的题解了qwq

hdu 2121 Ice_cream’s world II