2015暑假训练赛团体赛(DLX+Trie模糊匹配+费用流)

来源:互联网 发布:蹭网器密码破解软件 编辑:程序博客网 时间:2024/06/05 18:07

A - Sudoku Extension

Sudoku is a logic-based, combinatorial number-placement puzzle. The objective is to fill a 9 x 9 grid so that each column, each row, and each of the nine 3 x 3 boxes (also called blocks or regions) contains the digits from 1 to 9 only one time each. The puzzle setter provides a partially completed grid.[from wikipedia]

Left figure is the puzzle and right figure is one solution for that puzzle.

It’s a very common game for magazine and newspapers, and people like it for killing time. How about adding some features to this game, some cells can only be filled with even number, some cells can only be filled with odd number, and some cells can only be filled with the same number. Great, let’s call it “Sudoku Extension”.

It’s very easy to give one possible solution a Sudoku Extension puzzle, but do you know how many solutions are there for a certain Sudoku Extension problem? Let’s find out!

Input

The input data will start with the number of test cases. For each test case, 9 lines followed, corresponding to the rows of the table. On each line, a string of exactly 9 characters is given, it’s either 0-9 digit, or a-z alpha in lower case. 1' -9’ means the cell is already filled in; 0' means this cell is empty;e’ means the cell need to be filled with a even number; o' means the cell need to be filled with an odd number; other alpha ofa’ - z', excepte’ and o' denote a variable, so if two or more cells denoted bya’, then they must be filled with the same number.

Output

The output for each case is the number of possible solutions, note for each case, the solution will be less than 3000, and there are not more than 10 test cases.

Sample Input

1
040008007
00e030408
006000200
301004000
0080000o2
000003000
200401005
600070000
800006003

Sample Output

507
数独变形,DLX

#include<iostream>#include<cstdio>#include<string>#include<cstring>#include<vector>#include<cmath>#include<queue>#include<stack>#include<map>#include<set>#include<algorithm>using namespace std;const int maxn=9*9*9+10;const int maxm=9*9*4+10;const int maxnode=maxn*maxm;const int SIGMA_SIZE=9;const int SLOT=0;const int ROW=1;const int COL=2;const int SUB=3;struct DLX{    int n,m,size;    int U[maxnode],D[maxnode],L[maxnode],R[maxnode];    int H[maxn],S[maxm];    int row[maxnode],col[maxnode];    int ansd,ans[maxnode];    void init(int N,int M)    {        n=N,m=M;        ansd=0;        for(int i=0;i<=m;i++)        {            U[i]=D[i]=i;            L[i]=i-1;            R[i]=i+1;        }        L[0]=m;        R[m]=0;        size=m;        memset(S,0,sizeof(S));        memset(H,-1,sizeof(H));    }    void Link(int r,int c)    {        ++S[col[++size]=c];        row[size]=r;        D[size]=D[c];        U[D[c]]=size;        U[size]=c;        D[c]=size;        if(H[r]<0)H[r]=L[size]=R[size]=size;        else        {            R[size]=R[H[r]];            L[R[H[r]]]=size;            L[size]=H[r];            R[H[r]]=size;        }    }    void remove(int c)    {        L[R[c]]=L[c];R[L[c]]=R[c];        for(int i=D[c];i!=c;i=D[i])        {            for(int j=R[i];j!=i;j=R[j])            {                U[D[j]]=U[j];                D[U[j]]=D[j];                --S[col[j]];            }        }    }    void restore(int c)    {        for(int i=U[c];i!=c;i=U[i])        {            for(int j=L[i];j!=i;j=L[j])            {                U[D[j]]=D[U[j]]=j;                ++S[col[j]];            }        }        L[R[c]]=R[L[c]]=c;    }    void Dance(int d)    {        if(R[0]==0)        {            ansd++;            return;        }        int c=R[0];        for(int i=R[0];i;i=R[i])            if(S[i]<S[c])c=i;        remove(c);        for(int i=D[c];i!=c;i=D[i])        {            ans[d]=row[i];            for(int j=R[i];j!=i;j=R[j])remove(col[j]);            Dance(d+1);            for(int j=L[i];j!=i;j=L[j])restore(col[j]);        }        restore(c);    }}dlx;int encode(int a,int b,int c){    return a*81+b*9+c;}void decode(int code,int &a,int &b,int &c){    code--;    c=code%9;code/=9;    b=code%9;code/=9;    a=code;}char str[maxn][maxn];vector<pair<int,int> > alp[30];int main(){     int T;    scanf("%d",&T);    while(T--)    {        for(int i=0;i<9;i++)scanf("%s",&str[i]);        dlx.init(9*9*9,9*9*4);        for(int r=0;r<SIGMA_SIZE;r++)            for(int c=0;c<SIGMA_SIZE;c++)                for(int v=1;v<=SIGMA_SIZE;v++)                {                    if(str[r][c]=='0'||str[r][c]==v+'0')                    {                        int row=encode(r,c,v);                        dlx.Link(row,encode(SLOT,r,c)+1);                        dlx.Link(row,encode(ROW,r,v));                        dlx.Link(row,encode(COL,c,v));                        dlx.Link(row,encode(SUB,(r/3)*3+c/3,v));                    }                    else if((str[r][c]=='o'&&v%2==1)||(str[r][c]=='e'&&v%2==0))                    {                        int row=encode(r,c,v);                        dlx.Link(row,encode(SLOT,r,c)+1);                        dlx.Link(row,encode(ROW,r,v));                        dlx.Link(row,encode(COL,c,v));                        dlx.Link(row,encode(SUB,(r/3)*3+c/3,v));                    }                }        for(int i=0;i<=26;i++)alp[i].clear();        for(int i=0;i<9;i++)            for(int j=0;j<9;j++)                if(isalpha(str[i][j])&&str[i][j]!='o'&&str[i][j]!='e')                    alp[str[i][j]-'a'].push_back(make_pair(i,j));        for(int i=0;i<26;i++)        {            int len=alp[i].size();            for(int j=0;j<len;j++)            {                for(int v=1;v<=9;v++)                {                    int r=alp[i][j].first,c=alp[i][j].second;                    int row=encode(r,c,v);                    for(int p=j;p<len;p++)                    {                        r=alp[i][p].first,c=alp[i][p].second;                        dlx.Link(row,encode(SLOT,r,c)+1);                        dlx.Link(row,encode(ROW,r,v));                        dlx.Link(row,encode(COL,c,v));                        dlx.Link(row,encode(SUB,(r/3)*3+c/3,v));                    }                }            }        }        dlx.Dance(0);        printf("%d\n",dlx.ansd);    }    return 0;}

G - Fuzzy Google Suggest

Google Suggest is a typical feature of the Google search box. It guesses what you’re typing and offers suggestions in real time(Fig 1). Sometimes, we may mistype the keyword. For example, when we want to find the information of mcgrady"(a famouse NBA star), we mistyped it tomacgrady”(Fig 2). The clever Google can still give you the right suggestions. It is amazing, isn’t it?

In this problem, your job is to implement a similar system. You will be given a data set including a large amount of English words. Your system should provide the search service. For each input query word, find the prefix-fuzzy-match words from the data set and ouput the number of those words. In the following, I will explain you the prefix fuzzy match. When we say the two words are fuzzy-match (without prefix"), we mean that they look similar and their Edit Distance meets a given threshold (If you have no idea of the Edit Distance, please refer to the Hints below). When we say the word A is prefix-fuzzy-match (withprefix”) to the word B, we mean that there exists a prefix p of word B, and the Edit Distance between p and B meets a given threshold. For Example, the data set contains four English words: content",common”, onganize",case”. The input query contains a word con" and a Edit Distance threshold 1.con” is prefix-fuzzy-match to the words content",common”, onganize", butcase” doesn’t meet the condition, because the minimun Edit Distance between all of its prefixes and “con” is 2 which is larger than the given threshold 1.

Input

The input file consists of two parts. The first part is a data set with n(1n300, 000) English words. The second part is the m(1m300) input queries. Each query has a word and an Edit Distance threshold edth(0edth2), separated by a space. The words in the data set and the queries contain at most 10 small letters (a-z).

Output

For each input query, output the number of words from data set that the query word is prefix-fuzzy-match to.

Hints(From Wikipedia):

The Edit Distance between two strings is given by the minimum number of operations needed to transform one string into the other, where an operation is an insertion, deletion, or substitution of a single character. For example, the Edit Distance between kitten" andsitting” is 3, since the following three edits change one into the other, and there is no way to do it with fewer than three edits:

kitten $ \rightarrow$ sitten (substitution of `s' for `k')sitten $ \rightarrow$ sittin (substitution of `i' for `e')sittin $ \rightarrow$ sitting (insert `g' at the end). 

Sample Input

4
content
common
onganize
case
7
c 0
con 0
con 2
con 1
com 1
comm 2
cog 1

Sample Output

3
1
4
3
2
2
2
思路:建立Trie,然后dfs

#include<iostream>#include<cstdio>#include<string>#include<cstring>#include<vector>#include<cmath>#include<queue>#include<stack>#include<map>#include<set>#include<algorithm>using namespace std;typedef long long LL;const int maxn=300010;const int maxm=1010;const int maxnode=maxn*11;const int SIGMA_SIZE=26;const int MOD=1e9+7;const int INF=0x3f3f3f3f;char s[30];int N,Q;int ans;struct Trie{    int ch[maxnode][SIGMA_SIZE];    int val[maxnode],vis[maxnode],is_end[maxnode];    int sz;    void clear(){memset(ch[0],-1,sizeof(ch[0]));sz=1;}    int idx(char x){return x-'a';}    void insert(char *s)    {        int u=0;        for(int i=0;s[i];i++)        {            int c=idx(s[i]);            if(ch[u][c]==-1)            {                memset(ch[sz],-1,sizeof(ch[sz]));                val[sz]=0;                ch[u][c]=sz++;            }            val[u]++;            u=ch[u][c];        }        val[u]++;    }    void dfs(int u,char *s,int x)    {        if(s[0]=='\0')        {            is_end[u]=1;            return;        }        vis[u]=1;        if(!x)        {            if(ch[u][s[0]-'a']!=-1)                dfs(ch[u][s[0]-'a'],s+1,x);            return ;        }        //匹配        if(ch[u][s[0]-'a']!=-1)dfs(ch[u][s[0]-'a'],s+1,x);        //删除        dfs(u,s+1,x-1);        //替换        for(int i=0;i<26;i++)            if(ch[u][i]!=-1&&i!=s[0]-'a')dfs(ch[u][i],s+1,x-1);        //插入        for(int i=0;i<26;i++)            if(ch[u][i]!=-1)dfs(ch[u][i],s,x-1);    }    void find(int u)    {        if(is_end[u])        {            ans+=val[u];            return;        }        if(!vis[u])return ;        for(int i=0;i<26;i++)        {            if(ch[u][i]!=-1)                find(ch[u][i]);        }    }    void solve(char *s,int x)    {        ans=0;        memset(vis,0,sizeof(vis));        memset(is_end,0,sizeof(is_end));        dfs(0,s,x);        find(0);        printf("%d\n",ans);    }}tree;int main(){    while(scanf("%d",&N)!=EOF)    {        scanf("%d",&N);        tree.clear();        for(int i=1;i<=N;i++)        {            scanf("%s",s);            tree.insert(s);        }        scanf("%d",&Q);        while(Q--)        {            int x;            scanf("%s%d",s,&x);            tree.solve(s,x);        }    }    return 0;}

D - Gold Mines

One day, N rogues find a treasure map in accident, so they decide to go along with each other to hunt the treasure in an isolate island. This island can be considered as an undirected graph with V vertexes, each of which is a land.

The edge between two vertexes means there is a road connecting to the correspond lands. After a great effort, these rogues finally find 2 *N lands which contain gold mines. They must divide the lands equally, so each rogue should get two mines. And several additional lands should be assigned to each rogue in order that he can reach one gold mine from the other one by merely passing the lands belonging to him. Being too selfish to share a land with each other, they have quarreled about how to divide the lands for many days.

Being the guardian of this island, you must try your best to protect it. If you manage to make a plan to meet their requirement, the lands which are not assigned to any rogues can be protected. You know there is a price for each land, so you must maximize the sum of price of the lands not assigned.

Input

Input consists of many test cases. The first line is an integer T which is the amount of cases. The first line of each case are two integer numbers V and E with 1V500 and 0EV* (V - 1)/2, where V is the amount of lands and E is the amount of roads. Next E lines each contains two numbers vi and vj which denotes there is a road between lands vi and vj. The next integer is N with 1N4, the amount of rouges. Then 2 *N integers follow which denote the 2 *N lands containing gold mines. The last V positive integers are price of all lands. Lands are numbered from 0 to V - 1.

Output

For each test case, print a line containing a single integer which is the maximum price not assigned when the rouges’ requirement is met. Print `-1’ if no feasible assignment exists.

Sample Input

2
9 5
0 1
2 3
4 5
6 7
7 8
4 0 1 2 3 4 5 6 7
1 1 1 1 1 1 1 1 1
9 0
4 0 1 2 3 4 5 6 7
1 1 1 1 1 1 1 1 1

Sample Output

1
-1
思路:最小费用流,暴力将2*N分成两组,然后拆点,求最小费用最大流

#include<iostream>#include<cstdio>#include<string>#include<cstring>#include<vector>#include<cmath>#include<queue>#include<stack>#include<map>#include<set>#include<algorithm>using namespace std;typedef long long LL;const int maxn=1020*2;const int maxm=1000100;const int MOD=1e9+7;const int INF=0x3f3f3f3f;int N,M,man;int gold[maxn],cost[maxn];int a[maxn],b[maxn];struct node1{    int f,next,cost,v,u;} edge[maxm*2];int pre[maxn],head[maxn],dis[maxn];bool vis[maxn];int s,t,num;void init(){    num=0;    memset(head,-1,sizeof(head));}void add_edge(int u,int v,int f,int cost){    edge[num].u=u;    edge[num].v=v;    edge[num].cost=cost;    edge[num].f=f;    edge[num].next=head[u];    head[u]=num++;    edge[num].v=u;    edge[num].u=v;    edge[num].cost=-cost;    edge[num].f=0;    edge[num].next=head[v];    head[v]=num++;}void build(int S){    s=0,t=2*N+1;    init();    for(int i=0;i<(2*man);i++)        if(S&(1<<i))add_edge(s,gold[i],1,0);        else add_edge(gold[i]+N,t,1,0);    for(int i=1;i<=N;i++)        add_edge(i,i+N,1,cost[i]);    for(int i=0;i<M;i++)        add_edge(a[i]+N,b[i],INF,0),        add_edge(b[i]+N,a[i],INF,0);}bool spfa(int s,int t){    int cur;    for(int i=0; i<=t+2; i++)    {        dis[i]=INF;        vis[i]=0;        pre[i]=-1;    }    queue<int> q;    q.push(s);    dis[s]=0;    vis[s]=true;    while(!q.empty())    {        cur=q.front();        q.pop();        vis[cur]=0;        for(int i=head[cur]; i!=-1; i=edge[i].next)        {            if(edge[i].f>0)            {                int v=edge[i].v;                if(dis[v]>dis[cur]+edge[i].cost)                {                    dis[v]=dis[cur]+edge[i].cost;                    pre[v]=i;                    if(!vis[v])                    {                        vis[v]=1;                        q.push(v);                    }                }            }        }    }    if(dis[t]!=INF)        return true;    return false;}int mincost(){    int i,flow=INF,ans=0;    int sumflow=0;    while(spfa(s,t))    {        flow=INF;        for(i=pre[t]; i!=-1; i=pre[edge[i].u])            flow=min(flow,edge[i].f);        sumflow+=flow;        for(i=pre[t]; i!=-1; i=pre[edge[i].u])        {            ans+=flow*edge[i].cost;            edge[i].f-=flow;            edge[i^1].f+=flow;        }    }    if(sumflow==man)return ans;    return -1;}int main(){    int T;    scanf("%d",&T);    while(T--)    {        scanf("%d%d",&N,&M);        for(int i=0;i<M;i++)        {            scanf("%d%d",&a[i],&b[i]);            a[i]++;            b[i]++;        }        scanf("%d",&man);        for(int i=0;i<2*man;i++)        {            scanf("%d",&gold[i]);            gold[i]++;        }        int sum=0;        for(int i=1;i<=N;i++)        {            scanf("%d",&cost[i]);            sum+=cost[i];        }        int ans=INF;        for(int S=0;S<(1<<(2*man));S++)        {            int cnt=0;            for(int i=0;i<2*man;i++)                if(S&(1<<i))cnt++;            if(cnt!=man)continue;            build(S);            int all=mincost();            if(all>=0)ans=min(ans,all);        }        if(ans<=sum)ans=sum-ans;        else ans=-1;        printf("%d\n",ans);    }    return 0;}
0 0
原创粉丝点击