24/7/2012 ICPC培训 第九天

来源:互联网 发布:spark 用户画像算法 编辑:程序博客网 时间:2024/04/30 11:36

又来吐吐糟啦。。。

今天还算顺利,总共刷出了5题。

前两题是并查集,就是昨天没搞定的奋斗。后面三题都是最短路径了。

 

简单说说这几题吧。

关于并查集的两题其实都是卡在了路径压缩的处理上。很坑爹的说。其实也就是在路径压缩时

利用数组记录下一些信息。在需要的时候在合理的计算出来。

其实,挺难理解的抓狂。。。

我也只是一知半解了。。。

 

第一题(HDU1829)

主要是判断两个人是否在同一连通分量的同一层次上。那个计算层次的两个公式,较难理解。

代码:

#include<iostream>#include<cstring> using namespace std;const int maxn=2001;int father[maxn],layer[maxn],numBug,actionBug;bool flag;void init(){    memset(layer,0,sizeof(layer));         for(int i=1;i<=numBug;i++)    {        father[i]=i;    }}int find(int x){    if(x!=father[x])    {        int tmp=father[x];         father[x]=find(father[x]);         layer[x]=(layer[x]+layer[tmp])%2;    }        return father[x]; }void combine(int x,int y){    int fx=find(x);    int fy=find(y);        if(fx==fy)    {        if(layer[x]==layer[y])  flag=true;          }    else    {        father[fx]=fy;        layer[fx]=(layer[x]+layer[y]+1)%2;     }}void deal(){    flag=false;        int x,y;    for(int i=1;i<=actionBug;i++)    {        scanf("%d%d",&x,&y);        if(!flag) combine(x,y);    }}        int main(){    int cas,t=1;        scanf("%d",&cas);    while(cas--)    {        scanf("%d%d",&numBug,&actionBug);                init();                deal();                printf("Scenario #%d:\n",t++);        if(flag) printf("Suspicious bugs found!\n\n");        else printf("No suspicious bugs found!\n\n");    }        system("pause");     return 0;}

 

第二题(HDU3635)

这题的难点在于求ball的转移次数。

暴力解法是每次Q A时都暴力找到和A同祖先的ball,然后把转移次数加一,O(n^2)的算法,TLE了。

另外的解法就是在路径压缩时利用路径压缩的特点来解,难点也就是这个了。

如果你是我的祖先,你的转移次数加上我的转移次数才是我的转移次数,否则你早已不是我的祖先

了。只有直接转移祖先路径才不会被压缩,否则压缩。

代码:

#include<iostream>#include<cstring>using namespace std;const int maxn=10001;int father[maxn];int transport[maxn];int numBall[maxn]; int N,K,t=1;int find(int x){    if(x!=father[x])    {        int temp=father[x];        father[x]=find(father[x]);        transport[x]+=transport[temp];    }        return father[x];        //if(x==father[x])    //{    //    return x;    //}        //return father[x]=find(father[x]);}void combine(int x,int y){    int fx=find(x);    int fy=find(y);        if(fx==fy) return;        father[fx]=fy;    transport[fx]++;    numBall[fy]+=numBall[fx];}void init(){    memset(transport,0,sizeof(transport));        for(int i=1;i<=N;i++)    {        father[i]=i;        numBall[i]=1;    }} void inputAndQuary(){    int i,a,b;    char ch;        printf("Case %d:\n",t++);         for(i=0;i<K;i++)    {        getchar();            scanf("%c",&ch);                if(ch=='T')        {            scanf("%d%d",&a,&b);                        combine(a,b);        }        else        {            scanf("%d",&a);                        int tmp=find(a);            printf("%d %d %d\n",tmp,numBall[tmp],transport[a]);        }    }}                                  int main(){    int cas;        scanf("%d",&cas);    while(cas--)    {        scanf("%d%d",&N,&K);                init();                   inputAndQuary();    }        system("pause");    return 0;}

 

后面三题全是最短路径问题。(HDU2066、2544、1874)

还都是用SPFA算法来解的。代码都非常相似,我就放在一次讲啦。

不过,问题时我用模板过了2066、2544,却卡在了1874,数次WA呀。。。

这就让我纠结了。

神马情况呀。前面都过了。

找这种错误是最难的,最纠结的。因为我认为木有问题呀。从逻辑到数据都是经过检验的呀。

花了很长时间,一直忍着没找度娘。功夫不负有心人呀。最后发现模板中有一个函数的代码

有问题惊恐,就这样也过了2066、2544。。。这数据没的说了。。。

代码:

#include<iostream>#include<vector>#include<queue>#include<cstring>using namespace std;const int maxn=1001;const int INF=0x7fffffff;struct node{    int to;    int cost;};vector<node> myV[maxn];  //利用临界表存储图 int numRoad,numFrom,numTo; //路径数、可以开始的地点数、想去的地点数 int minPath[maxn],canFrom[maxn],wantTo[maxn]; //最短路、可以出发的城市、想去的城市 bool inQ[maxn];  //是否入队 /*  有bug的函数 bool judgeExistAndSmall(int a,int b,int time){    bool flag=false;        for(int i=0;i<myV[a].size();i++)    {         if(myV[a][i].to==b)        {            if(myV[a][i].cost>time)            {                myV[a][i].cost=time;                flag=true;                break;            }        }    }        if(flag)    {        for(int j=0;j<myV[b].size();j++)        {            if(myV[b][j].to==a)            {                myV[b][j].cost=time;                break;            }        }    }        if(flag) return true;    return false;}*/bool judgeExistAndSmall(int a,int b,int time){    bool flagExist=false,flagSmall=false;  //路径是否存在、存在的路径是否更小         for(int i=0;i<myV[a].size();i++)    {         if(myV[a][i].to==b)        {            flagExist=true;             if(myV[a][i].cost>time)            {                myV[a][i].cost=time;                flagSmall=true;                break;            }        }    }        if(flagSmall)  //双向图,只有存在的路径更小才需要处理     {        for(int j=0;j<myV[b].size();j++)        {            if(myV[b][j].to==a)            {                myV[b][j].cost=time;                break;            }        }    }        if(flagExist) return true;   //只要存在路径就返回true     return false;}     void inputItial(){    int i,a,b,time;        for(i=0;i<maxn;i++)  //清空再使用     {        myV[i].clear();    }        for(i=0;i<numRoad;i++)    {        scanf("%d%d%d",&a,&b,&time);                if(!judgeExistAndSmall(a,b,time))  //无向图、判断是否存在了路、存在的路是大是小         {            node tmp;            tmp.cost=time;                        tmp.to=b;            myV[a].push_back(tmp);                        tmp.to=a;            myV[b].push_back(tmp);                  }    }        for(i=0;i<numFrom;i++)    {        scanf("%d",&canFrom[i]);    }        for(i=0;i<numTo;i++)    {        scanf("%d",&wantTo[i]);    }}        void SPFA()   //最短路径快速算法 Shortest Path Faster Algorithm{    int minCost=INF;        for(int i=0;i<numFrom;i++)    {        memset(inQ,false,sizeof(inQ));        for(int j=0;j<maxn;j++)        {            minPath[j]=INF;        }        minPath[canFrom[i]]=0;                queue<int> myQ;        myQ.push(canFrom[i]);        inQ[canFrom[i]]=true;                int now,to,cost;        while(!myQ.empty())        {            now=myQ.front();            myQ.pop();                        for(int k=0;k<myV[now].size();k++)            {                to=myV[now][k].to;                cost=myV[now][k].cost+minPath[now];                if(minPath[to]>cost)                {                    minPath[to]=cost;                                        if(!inQ[to])                    {                        inQ[to]=true;                        myQ.push(to);                    }                }            }                        inQ[now]=false;        }                for(int kk=0;kk<numTo;kk++)        {            minCost=min(minCost,minPath[wantTo[kk]]);        }    }        printf("%d\n",minCost);}     int main(){    while(scanf("%d%d%d",&numRoad,&numFrom,&numTo)==3)    {        inputItial();                SPFA();    }     system("pause");       return 0;}


 

最后,到这么晚才写实在不好意思。

看电视的说大笑。。。

 

 

 

 

 

原创粉丝点击