矩阵的并 容斥原理

题意 :给出了n个矩阵, (n<=20), 现在有m(m<=100000)个询问, 要问若干个矩阵的并是多少。

 

思路: 开始的时候一直认为这道题是用线段树做, 后来发现原来也可以用容斥原理做,原因是n比较小。 比较暴力,但是有剪枝的地方。 即无论如何都不会有面积出现就break。

k个矩阵的并 = 1个矩阵的面积和 - 2个面积交的和+3。。。。。

AC代码:

 

View Code
#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
using namespace std;

struct
{
    int x0, y0, x1, y1;
} p[21];
int ans[1<<21], ask[1<<21], n, m;

inline void in(int &a)
{
    char ch;
    while(ch = getchar(), ch < '0' || ch > '9');
    a = ch - '0';
    while(ch = getchar(), ch >= '0' && ch <= '9')
    {
        a = a * 10 + ch - '0';
    }
    return;
}

void init()
{
    for(int i=0; i<n; i++)
    {
        in(p[i].x0);
        in(p[i].y0);
        in(p[i].x1);
        in(p[i].y1);
    }
    int t, x;
    memset(ans, 0, sizeof(ans));
    for(int i=1; i<=m; i++)
    {
        in(t);
        ask[i] = 0;
        while(t--)
        {
            in(x);
            ask[i] |= 1<<(x-1);
        }
    }
}

void solve()
{
    int x0, y0, x1, y1, tp;
    for(int i=1; i<(1<<n); i++)
    {
        x0 = 0, y0 = 0;
        x1 = 1000, y1 = 1000;
        bool flag = 1;
        tp = 0;
        for(int j=0; j<n; j++)
        {
            if((1<<j)&i)
            {
                tp++;
                x0 = max(x0,p[j].x0);
                y0 = max(y0,p[j].y0);
                x1 = min(x1,p[j].x1);
                y1 = min(y1,p[j].y1);
                if(x0 >= x1 || y0 >= y1)
                {
                    flag = 0;
                    break;
                }
            }
        }
        if(flag)
         {
             for(int j=1; j<=m; j++)
              {
                  if( (ask[j]|i) == ask[j])
                   {
                       if(tp%2)
                        {
                            ans[j] += (x1-x0)*(y1-y0);
                        }
                       else ans[j] -= (x1-x0)*(y1-y0);
                   }
              }
         }
    }

   for(int i=1; i<=m; i++)
    {
        printf("Query %d: %d\n", i, ans[i]);
    }
}

int main()
{
    int t = 0;
    while(scanf("%d%d", &n, &m) != EOF)
    {
        if(n == 0 && m == 0)
         break;
        t++;
        init();
        printf("Case %d:\n", t);
        solve();
        printf("\n");
    }
   return 0;
}

 

 

 

posted @ 2012-09-26 20:43  Gu Feiyang  阅读(355)  评论(0)    收藏  举报