• CTSC 2001 – Day 1 – Agent

终极情报网

 

【题目叙述】
在最后的诺曼底登陆战开始之前,盟军与德军的情报部门围绕着最终的登陆地点展开了一场规模空前的情报战。
这场情报战中,盟军的战术是利用那些潜伏在敌军内部的双重间谍,将假的登陆消息发布给敌军的情报机关的负责人。那些已经潜入敌后的间谍们都是盟军情报部的精英,忠实可靠;但是如何选择合适的人选,以及最佳的消息传递方法,才能保证假消息能够尽快而且安全准确地传递到德军指挥官们的耳朵里,成了困扰盟军情报部长的最大问题。他需要你的帮助。
 
以下是情报部长提供的作战资料:
 
在敌后一共潜伏着我方最优秀的N名间谍,分别用数字1, 2, …, N编号。在给定的作战时间内,任意两人之间至多只进行一次点对点的双人联系。
我将给你一份表格,表格中将提供任意两位间谍ij之间进行联系的安全程度,用一个 [0, 1] 的实数Si j表示;以及他们这次联系时,能够互相传递的消息的最大数目,用一个正整数表示Mi j (如果在表格中没有被提及,那么间谍ij之间不进行直接联系)
假消息从盟军总部传递到每个间谍手里的渠道也不是绝对安全,我们用 [0, 1] 的实数ASj表示总部与间谍j之间进行联系的安全程度,AMj则表示总部和间谍j之间进行联系时传递的消息的最大数目。对于不和总部直接联系的间谍,他的AMj=0(而表格中给出的他的ASj是没有意义的)。
当然,假消息从间谍手中交到敌军的情报部官员的办公桌上的过程是绝对安全的,也即是说,间谍与敌军情报部门之间要么不进行直接联系,要么其联系的安全程度是1(即完全可靠)。
 
现在情报部打算把K条假消息“透露”到德军那里。消息先由总部一次性发给N名间谍中的一些人,再通过他们之间的情报网传播,最终由这N名间谍中的某些将情报送到德军手中。对于一条消息,只有安全的通过了所有的中转过程到达敌军情报部,这个传递消息的过程才算是安全的;因此根据乘法原理,它的安全程度P就是从总部出发,经多次传递直到到达德军那里,每一次传递该消息的安全程度的乘积而对于整个计划而言,只有当N条消息都安全的通过情报网到达德军手中,没有一条引起怀疑时,才算是成功的。所以计划的可靠程度所有消息的安全程度的乘积显然,计划的可靠性取决于这些消息在情报网中的传递方法。
 
我需要一个方案,确定消息应该从哪些人手中传递到哪些人手中,使得最终计划的可靠性最大。你可以利用计算机,来求得这个最可靠的消息传递方案。
 
【输入文件】
输入文件agent.in包含了盟军的作战资料表格。
第一行包括两个整数NK,分别是间谍的总人数和计划包含的消息总数。
第二行包括2N个数,前N个数是实数AS1, AS2, …, ASN(范围在[0, 1]以内);后N个数是整数AM1, AM1, …, AMN
第三行包含了N个整数,其中第ii = 1, 2, …, N)个整数如果为0表示间谍i与德军情报部不进行联系,如果为1则表示间谍与德军情报部进行联系。
第四行开始,每行包括4个数,依次分别是:代表间谍编号的正整数ij,间谍ij联系的安全性参数Si j[01]范围内的实数),以及ij之间传递的最大消息数 Mi j(每一行的i均小于j )。
最后的一行包含两个整数-1  -1,表示输入数据的结束。
0<N<3000<K<300
 
【输出文件】
输出文件agent.out中只有一行。这一行中包含一个实数P,给出的是整个计划的可靠程度P,保留5位有效数字(四舍五入)。
如果情报网根本不能将K条消息传到德军手中,那么计划的可靠性为0你可以假定,如果计划存在,那么它的可靠性大于1e-12
 
【输入输出样例】

Agent.in
Agent.out
6  13
0.9  0.7  0.8  0  0  0  2  6  8  0  0  0
0  0  0  1  0  1
1  4  0.5  2
2  3  0.9  5
2  5  0.8  2
2  6  0.8  7
3  5  0.8  2
5  6  0.8  4
-1  -1
0.00021184
    
代码实现如下:[注意精度控制]
#include <iostream>
#include <fstream>
#include <iomanip>
#include <math.h>
//CTSC 2001 – Day 1 – Agent
//0<N<300;0<K<300
using namespace std;
const int MAXN=301, MAXE=91000;
typedef struct Edge{
    int i, j, next, op, f, c;
    double w;
}Edge;
Edge es[MAXE];
int eid, n, k, first[MAXN], pre[MAXN], ptr[MAXN], an[MAXN];//for each input edge
double as[MAXN], w[MAXN]/*cost*/;
//declaration
void addEdge(int i, int j, int c, double w);
int expandPath(int sv, int st);
void clr();
//implementation
void addEdge(int i, int j, int c, double w){
    if(!c) return;
    es[eid].i=i, es[eid].j=j, es[eid].c=c, es[eid].w=w;
    es[eid].next=first[i], first[i]=eid, es[eid].op=eid+1; eid++;
    es[eid].i=j, es[eid].j=i, es[eid].c=-1, es[eid].w=-w;
    es[eid].next=first[j], first[j]=eid, es[eid].op=eid-1; eid++;
}
void clr(){
    memset((void*)first, 0xff, sizeof(first)), eid=0;
}
int expandPath(int sv, int st){
    memset((void*)pre, 0xff, sizeof(pre));
    for(int i=1; i<=n+1; i++) w[i]=(double)INT_MAX;
    pre[sv]=sv, w[sv]=0.0;
    bool change=false;
    do{
        change=false;
        for(int i=1; i<=n+1; i++){
            for(int e=0; e<eid; e++){
                if(pre[es[e].i]!=-1){//already exits previous node
                    if(es[e].c>es[e].f){
                        if(w[es[e].i]+es[e].w+1e-13<w[es[e].j]){
                            w[es[e].j]=w[es[e].i]+es[e].w, pre[es[e].j]=es[e].i, ptr[es[e].j]=e, change=true;
                        }
                    }
                    if(es[e].c==-1&&es[e].f>0){
                        if(w[es[e].i]+es[e].w+1e-13<w[es[e].j]){
                            w[es[e].j]=w[es[e].i]+es[e].w, pre[es[e].j]=es[e].i, ptr[es[e].j]=e, change=true;
                        }
                    }
                }
            }
        }
    }while(change);
    if(pre[st]==-1) return 0;
    //calculate the maxflow
    int i=st, a=INT_MAX, value;
    for(;i!=sv; i=pre[i]){
        if(es[ptr[i]].c>es[ptr[i]].f){
            if((value=es[ptr[i]].c-es[ptr[i]].f)<a) a=value;
        }
        if(es[ptr[i]].c==-1&&es[ptr[i]].f>0){
            if((value=es[ptr[i]].f)) a=value;
        }
    }
    return a;
}
#define fbase
int main()
{
#ifdef fbase
    ifstream in("AGENT.IN8");
    if(!in) return EXIT_FAILURE;
    cin.rdbuf(in.rdbuf());
#endif
    //implementation
    int start, end, mn, a;
    double ms, sec=0.0;
    //createGraph
    cin>>n>>k;
    for(int i=1; i<=n; i++) cin>>as[i];
    for(int i=1; i<=n; i++) cin>>an[i];
    clr();
    for(int i=1; i<=n; i++){
        if(as[i]!=0&&an[i]!=0)
            addEdge(0, i, an[i], -log(as[i]));
    }
    for(int i=1; i<=n; i++){
        cin>>ms;
        if(ms==1) addEdge(i, n+1, INT_MAX, 0);
    }
    while(cin>>start>>end&&start!=-1&&end!=-1){
        cin>>ms>>mn; addEdge(start, end, mn, -log(ms)), addEdge(end, start, mn, -log(ms));
    }
    //for maxflow
    a=expandPath(0, n+1);
    while(a!=0){//for first cycle
        for(start=n+1; start!=0; start=pre[start]){
            if(es[ptr[start]].c>es[ptr[start]].f) es[ptr[start]].f+=a, es[es[ptr[start]].op].f+=a;
            if(es[ptr[start]].c==-1&&es[ptr[start]].f>0) es[ptr[start]].f-=a, es[es[ptr[start]].op].f-=a;
        }
        if(k>=a) sec+=a*w[n+1], k-=a;
        else sec+=k*w[n+1], k=0;
        a=expandPath(0, n+1);
    }
    if(k!=0) cout<<0<<endl;
    else{
        sec=exp(-sec);
        if(sec>1e-12) cout<<setprecision(5)<<showpoint<<sec<<endl;
        else cout<<0<<endl;
    }
#ifdef fbase
    in.close();
#endif
    return 0;
}
#undef fbase
  • The Grand DinnerUVA 10249,再次证明了UVA测试数据的严谨性,很简单的一个建模,编码也很简单。老是WA,想不通,但相信UVA的权威性,仔细一查,发现自己的预流标进算法实现有个问题:进行Push操作后的顶点,可能会使得L链表的前项变为存在余流,怎么办呢?两个办法,一是用queue来存储有余流的顶点,但这样所有增流操作中都要进去FIFO操作,对算导的框架有些影响;二是有Push操作就将顶点放在最前面,这样也能保证所有的U前项都是无流点;再精细一点,可以用一个数组来作为顶点在L中的索引数组,如果当前的Push操作是关于U和前项点的,就在直接提前。[后者由于引入了一个N的数组,所以访问数组的效率基本和忽视Push的冗余操作时间基本一致,下面是UVA上的数据。]汗颜,有错的代码居然作为自己的框架,唉!即使是算导也不能不加思考的照模式画萨。

My Submissions

#
 
Problem
Verdict
Language
Run Time
Submission Date
7118858
Accepted
C++
0.880
2009-05-09 16:42:40
7118850
Accepted
C++
0.904
2009-05-09 16:40:57
7118813
Accepted
C++
0.868
2009-05-09 16:32:13
7118054
Wrong answer
C++
0.288
2009-05-09 11:05:05
当然,就题目而言,最好的办法是基于完全二分图的一个贪心算法,可以杀到0.1左右的,这里主要是验证预流标进算法的实现。所以略去了,再次警示自己,三思而后行,做程序要静下心来,尤其是框架算法切不可草率,这种模型算法错框架,就等于没做了
#include <iostream>
#include <fstream>
//UVA 10249 The Grand Dinner
using namespace std;
const int MAXN=130, MAXE=7400;
typedef struct Edge{
    int i, j, next, op, f, c;
}Edge;
Edge es[MAXE];
int m, n, eid, first[MAXN], hv[MAXN], ev[MAXN], l[MAXN], in[MAXN];
//declaration
void initialGraph();
void addEdge(int i, int j, int c);
bool discharge(int v);
bool push(int eid);
bool relabel(int v);
void Hpreflow();
void clr();
//implementation
void clr(){
    eid=0, memset((void*)first, 0xff, sizeof(int)*(n+m+2));
}
void addEdge(int i, int j, int c){
    if(!c) return;
    es[eid].i=i, es[eid].j=j, es[eid].f=0, es[eid].c=c;
    es[eid].next=first[i], first[i]=eid, es[eid].op=eid+1; eid++;
    es[eid].i=j, es[eid].j=i, es[eid].f=0, es[eid].c=-1;
    es[eid].next=first[j], first[j]=eid, es[eid].op=eid-1; eid++;
}
void initalGraph(){
    memset((void*)l, 0xff, sizeof(int)*(n+m+2));
    for(int i=0; i<n+m; i++) l[i]=i+1, in[i+1]=i;
    memset((void*)hv, 0, sizeof(int)*(n+m+2)), memset((void*)ev, 0, sizeof(int)*(n+m+2));
    hv[0]=m+n+1;
    for(int e=first[0]; e!=-1; e=es[e].next){
        if(es[e].c>0){
            es[e].f+=es[e].c, es[es[e].op].f+=es[e].c;
            ev[0]-=es[e].c, ev[es[e].j]+=es[e].c;
        }
    }
}
void Hpreflow(){
    initalGraph();
    int pos=0, u=l[pos];
    while(u!=-1){
        if(discharge(u)){//higher算导基础上的改进
            if(pos!=0){
                in[l[0]]^=in[u], in[u]^=in[l[0]], in[l[0]]^=in[u];//自己做的索引数组
                l[0]^=l[pos], l[pos]^=l[0], l[0]^=l[pos];

            }
            pos=0;
        }
        u=l[++pos];//next position
    }
}
bool relabel(int v){
    if(ev[v]<=0) return false;//here:bug
    int hmin=INT_MAX; bool tlabel=true;
    for(int e=first[v]; e!=-1; e=es[e].next){//in the residental graph
        if(es[e].c>es[e].f||(es[e].c==-1&&es[e].f>0)){
            if(hmin>hv[es[e].j]) hmin=hv[es[e].j];
            if(hv[es[e].j]<hv[v]) tlabel=false;
        }
    }
    if(tlabel){
        hv[v]=hmin+1; return true;
    }
    return false;
}
bool push(int eid){//first check is adminsiable-edge
    if(ev[es[eid].i]<=0||hv[es[eid].i]!=hv[es[eid].j]+1) return false;
    int flow=ev[es[eid].i];
    if(es[eid].c>es[eid].f){
        if(flow>(es[eid].c-es[eid].f)) flow=es[eid].c-es[eid].f;
        es[eid].f+=flow, es[es[eid].op].f+=flow;
        ev[es[eid].i]-=flow, ev[es[eid].j]+=flow;
        return true;
    }
    if(es[eid].c==-1&&es[eid].f>0){
        if(flow>es[eid].f) flow=es[eid].f;
        es[eid].f-=flow, es[es[eid].op].f-=flow;
        ev[es[eid].i]-=flow, ev[es[eid].j]+=flow;
        return true;
    }
    return false;
}
bool discharge(int u){
    int eid=first[u]; bool change=false;
    while(ev[u]>0){
        if(eid==-1) relabel(u), eid=first[u], change=true;//高度修改肯定要提前
        else if(hv[u]==hv[es[eid].j]+1&&(es[eid].c>es[eid].f||(es[eid].c==-1&&es[eid].f>0))){
            if(in[es[eid].j]<in[u]) change=true;//前项点的流入也需要提前,要精心和静心于代码,任何时候和情况下都不可浮躁!
            push(eid);
        }
        else eid=es[eid].next;
    }
    return change;
}
#define fbase
int main()
{
#ifdef fbase
    ifstream in("input.txt");
    if(!in) return EXIT_FAILURE;
    cin.rdbuf(in.rdbuf());
#endif
    int c, total, maxflow;
    //implementation
    while(cin>>m>>n&&m&&n){
        clr(); total=0, maxflow=0;
        for(int i=1; i<=m; i++){
            cin>>c, addEdge(0, i, c), total+=c;
            for(int j=n+m; j>=m+1; j–) addEdge(i, j, 1);
        }//for i->[1…m] with source and i->j, back-insert to linklist
        for(int i=m+1; i<=n+m; i++) cin>>c, addEdge(i, n+m+1, c);
        Hpreflow();
        if(total!=ev[n+m+1]) cout<<0<<endl;
        else{//for each team
            cout<<1<<endl;
            for(int i=1; i<=m; i++){
                for(int eid=first[i]; eid!=-1; eid=es[eid].next){
                    if(es[eid].f==1&&es[eid].c!=-1){
                        cout<<es[eid].j-m;
                        if(es[eid].next!=-1) cout<<" ";
                    }
                }
                cout<<endl;
            }
        }
    }
#ifdef fbase
    in.close();
#endif
    return 0;
}
#undef fbase
 
算法分析:恩,典型的组合题,LIS加最大流。主要考虑到最大流要做拆点操作,N->2N,好像不是很好,再想下,发现贪心就可以搞定了。用vector<int> len[1…MAXLIS]将其中每一项进行升序排列,对于一个当前长度i->Len[i]而言,若前面的存在两项,都比前面的项大,那么更大的那个是最优的;因为至少都和前面的一样长,类似于活动安排的贪心分析。
代码实现:
Ranking Submission Run Time Language Submission Date
50 7119938 0.008[最好的是0ms,好强的结果] C++ 2009-05-10 08:53:21
然后,看了下牛人的时间,基本都在0.001左右,想了下,可以在排序的那块改进,用插入排序来代替len[i].push_back,但没有找到STL的模板算法;应该用自己的代码会更快,这里就省去了。
#include <iostream>
#include <fstream>
#include <vector>
//uva 10546 the eagle’s nest
using namespace std;
const int MAXN=101;
int d[MAXN], lis[MAXN], n, k;//lis[0…100] for length of lis
vector<int> len[MAXN];
//declaration
int cmp(const int& t1, const int& t2);
//implementation
int cmp(const int& t1, const int& t2){
    return d[t1]<d[t2];//if true, t1->previous
}
#define fbase
int main()
{
#ifdef fbase
    ifstream in("input.txt");
    if(!in) return EXIT_FAILURE;
    cin.rdbuf(in.rdbuf());
#endif
    //implementation
    string str;
    int bsize=0, l, r, mid, ncase=1;
    while(cin>>n&&n){
        for(int i=1; i<=n; i++) cin>>str>>d[i];
        d[0]=0, memset((void*)lis, 0, sizeof(lis));
        for(int i=1; i<=bsize; i++) len[i].clear();//clear for len[i] vector
        bsize=0;
        for(int i=1; i<=n; i++){
            l=0, r=bsize;
            while(l+1<r){
                mid=l+(r-l)/2;
                if(d[i]<=d[lis[mid]]) r=mid;
                else l=mid;
            }
            if(d[i]<=d[lis[r]]) r=l;
            len[r+1].push_back(i);
            if(r+1>bsize)  bsize=r+1;
            if(lis[r+1]==0) lis[r+1]=i;
            else if(d[i]<d[lis[r+1]]) lis[r+1]=i;
        }
        for(int i=1; i<=bsize; i++) sort(len[i].begin(), len[i].end(), cmp);
        bool terminate=false;
        int nums=0, pre, next, cur;
        while(!terminate){
            pre=-1, next=0;
            for(int i=bsize; i>=1; i–){
                cur=pre;
                if(len[i].size()==0){terminate=true; break;}
                if(pre==-1){
                    pre=d[len[i][len[i].size()-1]], len[i].pop_back(); next++;
                }
                else{//pre!=-1
                    for(int j=len[i].size()-1; j>-1; j–){
                        if(pre>d[len[i][j]]){ pre=d[len[i][j]], len[i].pop_back(); next++; break;}
                        len[i].pop_back();
                    }
                }
                if(len[i].size()==0) terminate=true;
                if(pre==cur) break;
            }
            if(next==bsize) nums+=bsize;
        }
        cout<<"Case #"<<(ncase++)<<": "<<nums<<endl;
    }
#ifdef fbase
    in.close();
#endif
    return 0;
}
#undef fbase
 
  • pku1637 — Sightseeing tour,这又是一道模型题,混合图的欧拉回路。黑书上的描述近似于天书,IRJ的一句:“实际上就是给无向边定向”,网上的一个兄弟:“算出出度和入度之差”[由于有向欧路的出度,入度之差为偶数,0,这里少边的欧路点必然也是偶数],犯了一个错,忘记/2了;出度和入度之差是边的2倍,这点要注意,然后就是用FIFO的预流推进解最大流。忽然发现一个很简单的欧路实现,勾起了我对失败之至的欧拉回路回忆。做BOP review的时候,看怎么把那道题切掉吧,还有那道男人题。
    //代码写的很次,还是贴出来吧,为了警示自己和别人的差距还很大,加油哈!

Source Code

Problem: 1637 User: orlando22
Memory: 332K Time: 79MS//先做再改吧
Language: C++ Result: Accepted
  • Source Code
    #include <iostream>
    #include <math.h>
    
    //pku 1637, zju1992 sightseeing tour
    using namespace std;
    
    const int MAXN=202, MAXE=2400;//vertexs 200, edge 1000
    typedef struct Edge{
        int i, j, next, op, f, c;
    }Edge;
    Edge es[MAXE];
    int eid, m, s, first[MAXN], ev[MAXN], hv[MAXN], l[MAXN], head, tail;
    //helper array
    int inofv[MAXN];
    
    //declaration
    void clr();
    void addEdge(int s, int e, int c);
    void initialflow();
    void Hpreflow();
    void discharge(int v);
    bool push(int eid);
    bool relabel(int v);
    void inline EnDQ(int v);
    int inline DeDQ();
    
    //implementation
    void clr(){
        eid=0, memset((void*)first, 0xff, sizeof(first));
        memset((void*)inofv, 0, sizeof(inofv));
    }
    void addEdge(int s, int e, int c){
        if(!c) return;
        es[eid].i=s, es[eid].j=e, es[eid].f=0, es[eid].c=c;
        es[eid].next=first[s], first[s]=eid, es[eid].op=eid+1; eid++;
        es[eid].i=e, es[eid].j=s, es[eid].f=0, es[eid].c=-1;
        es[eid].next=first[e], first[e]=eid, es[eid].op=eid-1; eid++;
    }
    void Hpreflow(){
        initialflow();
        int u=DeDQ();
        while(u!=-1){
            discharge(u);
            u=DeDQ();
        }
    }
    void discharge(int v){
        int eid=first[v];
        while(ev[v]>0){
            if(eid==-1) relabel(v), eid=first[v];
            else if(hv[v]==hv[es[eid].j]+1&&(es[eid].c>es[eid].f||(es[eid].c==-1&&es[eid].f>0)))
                push(eid);
            else eid=es[eid].next;
        }
    }
    bool relabel(int v){
        if(ev[v]<=0) return false;
        int hmin=INT_MAX; bool tlabel=true;
        for(int e=first[v]; e!=-1; e=es[e].next){
            if(es[e].c>es[e].f||(es[e].c==-1&&es[e].f>0)){
                if(hv[es[e].j]<hmin) hmin=hv[es[e].j];
                if(hv[es[e].j]<hv[v]) tlabel=false;
            }
        }
        if(tlabel){
            hv[v]=hmin+1; return true;
        }
        return false;
    }
    bool push(int eid){
        if(ev[es[eid].i]<=0||hv[es[eid].i]!=hv[es[eid].j]+1) return false;
        int flow=ev[es[eid].i];
        if(es[eid].c>es[eid].f){
            if(es[eid].c-es[eid].f<flow) flow=es[eid].c-es[eid].f;
            es[eid].f+=flow, es[es[eid].op].f+=flow;
            ev[es[eid].i]-=flow, ev[es[eid].j]+=flow;
            if(ev[es[eid].j]>0) EnDQ(es[eid].j);
            return true;
        }
        if(es[eid].c==-1&&es[eid].f>0){
            if(es[eid].f<flow) flow=es[eid].f;
            es[eid].f-=flow, es[es[eid].op].f-=flow;
            ev[es[eid].i]-=flow, ev[es[eid].j]+=flow;
            if(ev[es[eid].j]>0) EnDQ(es[eid].j);
            return true;
        }
        return false;
    }
    void initialflow(){//for ev, hv, and l
        memset((void*)ev, 0, sizeof(ev)), memset((void*)hv, 0, sizeof(hv));
        head=tail=0;
        hv[0]=m+2;
        for(int eid=first[0]; eid!=-1; eid=es[eid].next){
            if(es[eid].c>0){
                es[eid].f+=es[eid].c, es[es[eid].op].f+=es[eid].c;
                ev[0]-=es[eid].c, ev[es[eid].j]+=es[eid].c;
                EnDQ(es[eid].j);
            }
        }
    }
    void inline EnDQ(int v){
        if(v==0||v==m+1) return;
        if((tail+1)%m==head) return;
        tail=(tail+1)%m;
        l[tail]=v;
    }
    int inline DeDQ(){
        if(tail==head) return -1;
        head=(head+1)%m;
        return l[head];
    }
    
    int main()
    {
        //implementation
        int ncase, a, b; bool single, possible;
        cin>>ncase;
        while(ncase--){
            clr();
            cin>>m>>s;
            for(int i=0; i<s; i++){
                cin>>a>>b>>single;
                inofv[a]++, inofv[b]--;
                if(!single) addEdge(a, b, 1);//for out edge
            }
            possible=true;
            for(int i=1; i<=m; i++){
                if((abs(inofv[i])&0x1)==1){
                    possible=false; break;
                }
            }
            if(possible){
                for(int i=1; i<=m; i++){
                    if(inofv[i]>0) addEdge(0, i, inofv[i]/2);//注意注意注意注意注意注意注意注意注意注意注意注意
                    else if(inofv[i]<0) addEdge(i, m+1, -inofv[i]/2);
                }
                Hpreflow();
                for(int e=first[0]; e!=-1; e=es[e].next){
                    if(es[e].c>0){
                        if(es[e].f!=es[e].c) possible=false;
                    }
                }
            }
            if(possible) cout<<"possible"<<endl;
            else cout<<"impossible"<<endl;
        }
    
        return 0;
    }
    

Advertisements