Antimatter Ray Clearcutting - UVa 11008 状压dp

Problem E
Antimatter Ray Clearcutting
Input: 
Standard Input

Output: Standard Output

It's year 2465, and you are the Chief Engineer for Glorified Lumberjacks Inc. on planet Trie. There is a number of trees that you need to cut down, and the only weapon you have is a high-powered antimatter ray that will cut through trees like butter. Fuel cells for the antimatter ray are very expensive, so your strategy is: stand somewhere in the forest and shoot the ray in some chosen direction. This will cut down all the trees that lie on the line in that direction. Given the locations of several trees and the number of trees that you are required to cut, what is the minimum number of shots that you need to fire?

Input

The first line of input gives the number of cases, N (at most 20). N test cases follow. Each one starts with 2 lines containing the integersn (the number of trees in the forest, at most 16) and m (the number of trees you need to cut, at most n). The next n lines will each give the (x,y) coordinates of a tree (integers in the range [-1000, 1000]).

Output

For each test case, output the line "Case #x:", where x is the number of the test case. On the next line, print the number of antimatter ray shots required to cut down at least m trees. Print an empty line between test cases.

 

Sample Input                               Output for Sample Input

2
4
4
0 0
0 1
1 0
1 1
9
7
0 0
1 1
0 2
2 0
2 2
3 0
3 1
3 2
3 4
Case #1:
2
 
Case #2:
2

 

Notes

In the first test case, you can cut down 4 trees by standing at (0, -1) and firing north (cutting 2 trees) and then standing at (1, -1) and again firing north (cutting 2 more trees).

In the second test case, you should stand at (3,-1) and fire north (cutting 4 trees) and then stand at (-1, -1) and fire north-east (cutting 3 more trees).


题意:在一个二维坐标轴上给你n个点,每次可以删除同在一条直线上的一些点,问至少删除m个点至少需要几次。

思路:用状压dp去枚举删除的两个点,同时删除同在这条直线上的点,可以预处理哪些点在通一条直线上……不过不预处理也不会超时,我是1.7秒多吧,就不改了。

AC代码如下:

#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
struct node
{ int x,y;
}dian[20];
vector <int> vc[20];
int dp[1000010],vis[1000010];
int num(int k)
{ int ans=0;
  while(k)
  { if(k&1)
     ans++;
    k/=2;
  }
  return ans;
}
int solve(int S,int m1,int m2)
{ int S2=S-(1<<(m1-1))-(1<<(m2-1));
  if(dian[m1].x==dian[m2].x && dian[m1].y==dian[m2].y)
   return S2;
  int k=S2,pos=1;
  while(k)
  { if(k&1)
    { if((dian[pos].x-dian[m1].x)*(dian[pos].y-dian[m2].y)==(dian[pos].x-dian[m2].x)*(dian[pos].y-dian[m1].y))
       S2-=(1<<(pos-1));
    }
    k/=2;
    pos++;
  }
  return S2;
}
int main()
{ int T,t,n,m,i,j,k,m1,m2,len,S,S2,ans;
  scanf("%d",&T);
  for(t=1;t<=T;t++)
  { scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)
     scanf("%d%d",&dian[i].x,&dian[i].y);
    for(i=0;i<=n;i++)
     vc[i].clear();
    vc[n].push_back((1<<n)-1);
    dp[(1<<n)-1]=0;
    for(i=n;i>0;i--)
    { len=vc[i].size();
      for(j=0;j<len;j++)
      { S=vc[i][j];
        for(m1=1;m1<=n;m1++)
        if(S&(1<<(m1-1)))
         for(m2=m1+1;m2<=n;m2++)
         if(S&(1<<(m2-1)))
         { S2=solve(S,m1,m2);
           if(vis[S2]==t)
            dp[S2]=min(dp[S2],dp[S]+1);
           else
           { dp[S2]=dp[S]+1;
             vc[num(S2)].push_back(S2);
             vis[S2]=t;
           }
         }
      }
    }
    ans=100000;
    if(n==m)
    { for(i=0;i<vc[0].size();i++)
       ans=min(ans,dp[vc[0][i]]);
      for(i=0;i<vc[1].size();i++)
       ans=min(ans,dp[vc[1][i]]+1);
    }
    else
    { for(i=0;i<=n-m;i++)
       for(j=0;j<vc[i].size();j++)
        ans=min(ans,dp[vc[i][j]]);
    }
    if(t!=1)
     printf("\n");
    printf("Case #%d:\n%d\n",t,ans);
  }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值