您的位置:首页 > 其它

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

2015-08-03 20:04 411 查看

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 of
a’ -
z', except
e’ and
o' denote a variable, so if two or more cells denoted by
a’, 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

[code]#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 to
macgrady”(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 (with
prefix”) 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", but
case” 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(1≤ \len≤ \le300, 000) English words. The second part is the m(1≤ \lem≤ \le300) input queries. Each query has a word and an Edit Distance threshold edth(0≤ \leedth≤ \le2), 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" and
sitting” 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:

[code]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

[code]#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 1≤ \leV≤ \le500 and 0≤ \leE≤ \leV* (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 1≤ \leN≤ \le4, 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分成两组,然后拆点,求最小费用最大流

[code]#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: