POI2011 Garbage

Garbage

POI2011

题意

1.每次清理车走的路是一个简单环

2.清理完之后环上所有的街道改变状态(脏->不脏,不脏->脏)

3.给出初始状态和终止状态

4.求一个合法的清理车清理方案。

1.如果初始状态与终止状态不一致,这条路就需要被清理

2.只需要存需要清理的边就行了
因为如果存在合法的方案,其中有覆盖不需要清理的边,那么这条边肯定被偶数个环经过,每两个环可以并成一个由全部需要清理的边组成的环

3.整理出边以后,就是找环,找一个每条边刚好被经过一次的环——欧拉回路
欧拉回路的具体操作:
①判连通(这里需要多个回路,所以这步省略)
②判度数,不能存在度数为奇数的点
③一遍搜过去,回溯时存下边
④一路上把经过的边直接标记
⑤最后按一定顺序输出

具体代码

#include
using namespace std;
typedef pair<int,int>P;
const int M=100005;
int n,m;
int head[M],asdf;
bool mark[M*10],vis[M];
int du[M],que[M*20],len;
vector<P>ans;
struct edge {
    int to,nxt,id;
} G[M*20];
void add_edge(int a,int b,int c) {
    G[++asdf].to=b;
    G[asdf].nxt=head[a];
    G[asdf].id=c;
    head[a]=asdf;
}
void dfs(int x) {
    vis[x]=1;
    for(int &i=head[x]; i; i=G[i].nxt) {
        if(mark[G[i].id])continue;
        int y=G[i].to;
        mark[G[i].id]=1;
        dfs(y);
        ans.push_back(P(x,y));
    }
}
int stk[M],top;
int cnt[M],po[M*100];
int main() {
    int a,b,x,y;
    scanf("%d %d",&n,&m);
    for(int i=1; i<=m; i++) {
        scanf("%d %d %d %d",&a,&b,&x,&y);
        if(x==y)continue;
        add_edge(a,b,i);
        add_edge(b,a,i);
        du[a]++,du[b]++;
        que[++len]=a,que[++len]=b;
    }
    sort(que+1,que+1+len);
    len=unique(que+1,que+1+len)-que-1;
    bool flag=1;
    for(int i=1; i<=len; i++) {
        if(du[que[i]]&1)flag=0;
    }
    if(!flag)printf("NIE\n");
    else {
        for(int i=1; i<=len; i++) {
            if(!vis[que[i]]) {
                dfs(que[i]);
            }
        }
        int sum=0;
        top=0;
        memset(cnt,0,sizeof(cnt));
        for(int i=ans.size()-1; i>=0; i--) {
            x=ans[i].first;
            if(!cnt[x])stk[++top]=x,cnt[x]++;
            y=ans[i].second;
            cnt[y]++;
            if(cnt[y]==2) {
                cnt[y]--;
                sum++;
                po[sum]=1;
                while(stk[top]!=y)cnt[stk[top--]]--,po[sum]++;
            } else stk[++top]=y;
        }
        printf("%d\n",sum);
        top=0;
        memset(cnt,0,sizeof(cnt));
        sum=0;
        for(int i=ans.size()-1; i>=0; i--) {
            x=ans[i].first;
            if(!cnt[x])stk[++top]=x,cnt[x]++;
            y=ans[i].second;
            cnt[y]++;
            if(cnt[y]==2) {
                cnt[y]--;
                sum++;
                printf("%d ",po[sum]);
                printf("%d ",y);
                while(stk[top]!=y) {
                    printf("%d ",stk[top]);
                    cnt[stk[top--]]--;
                }
                printf("%d\n",y);
            } else stk[++top]=y;
        }
    }
    return 0;
}

你可能感兴趣的:(POI题解,POI)